一文帶你簡單理解Vue的data為何只能是函數(shù)
前言
在學(xué)習(xí)vue的時(shí)候vue2只有在組件中嚴(yán)格要求data必須是一個(gè)函數(shù),而在普通vue實(shí)例中,data可以是一個(gè)對(duì)象,但是在vue3出現(xiàn)后data必須一個(gè)函數(shù),當(dāng)時(shí)看著官方文檔說的是好像是對(duì)象的引用問題,但是內(nèi)部原理卻不是很了解,今天通過一個(gè)簡單的例子來說明為啥data必須是一個(gè)函數(shù)
參考 (vue2data描述)
參考: (vue3data描述)
1.Vue3中的data
const { createApp } = Vue
const app = {
data: {
a: 1
},
template: `
<h1>{{a}}</h1>
`
}
createApp(app).mount('#app')
可以看到上來vue就給了警告說明data必須是一個(gè)函數(shù) 下面直接拋錯(cuò)
2.vue中的data
var app = new Vue({
el: '#app',
data: { a: 'hello world' }
})這種寫法是可以的,前面提過普通實(shí)例data可以是對(duì)象,但是在組件中必須是函數(shù), 那么在vue2中難道普通實(shí)例就沒有缺陷嘛?答案:是有缺陷的, 比如這樣
<div id="app1">{{ message }}</div>
<div id="app2">{{ message }}</div> const data = { message: 'hello world' }
const vue1 = new Vue({
el: '#app1',
data
})
const vue2 = new Vue({
el: '#app2',
data
})這樣在頁面中會(huì)顯示2個(gè)內(nèi)容為hello world的div標(biāo)簽 那么當(dāng)我們通過實(shí)例去改變messag呢?
vue1.message = 'hello Vue'

奇怪的事情發(fā)生了,我知識(shí)改變了vue1的實(shí)例中的數(shù)據(jù),但是其他實(shí)例的數(shù)據(jù)也發(fā)生了改變,相信很簡單就能看出來這應(yīng)該是共用同一個(gè)對(duì)象的引用而導(dǎo)致的,這在開放中是非常不友好的,開發(fā)者很容易就產(chǎn)生連串的錯(cuò)誤,vue2也知道這種缺陷只是沒有在普通實(shí)例中去體現(xiàn)而已,只在組件中實(shí)現(xiàn)了對(duì)于data的約束
為了讓大家更好的立即為啥data必須是一個(gè)函數(shù),黑貓?jiān)诖撕唵螌?shí)現(xiàn)一個(gè)vue的實(shí)例然后來證明為啥data是一個(gè)函數(shù),以及如果data不是一個(gè)函數(shù),我們應(yīng)該如何處理
3.證明data是函數(shù)以及原理實(shí)現(xiàn)
在實(shí)現(xiàn)簡單原理之前,我們需要搞清楚Vue在創(chuàng)建實(shí)例之前,對(duì)于data到底做了什么事情簡單來說就是:
vue 在創(chuàng)建實(shí)例的過程中調(diào)用data函數(shù)返回實(shí)例對(duì)象通過響應(yīng)式包裝后存儲(chǔ)在實(shí)例的data上并且實(shí)例可以直接越過data上并且實(shí)例可以直接越過data上并且實(shí)例可以直接越過data訪問屬性
1.通過這句描述可以知道Vue是一個(gè)構(gòu)造函數(shù),并且傳入的參數(shù)中有一個(gè)data的屬性,我們可以$data去訪問,也可以直接訪問這個(gè)屬性,并且我們需要對(duì)這個(gè)data做代理
那么簡單實(shí)現(xiàn)如下
function Vue(options) {
this.$data = proxy(options.data())
}
function proxy(options) {
return new Proxy(options, {
get(target, key, value, receiver) {
return Reflect.get(target, key, value, receiver)
},
set(target, key, newValue, receiver) {
Reflect.set(target, key, newValue, receiver)
}
})
}
const data = function () {
return {
a: 'hello world'
}
}
const vue1 = new Vue({
data
})
const vue2 = new Vue({
data
})
vue1.$data.a = 'hello Vue'
console.log(vue1.$data.a) // hello Vue
console.log(vue2.$data.a) // hello world通過簡單實(shí)現(xiàn)可與看出來,當(dāng)我們的data是一個(gè)函數(shù)的時(shí)候,在Vue的構(gòu)造函數(shù)中,只有有實(shí)例創(chuàng)建就有執(zhí)行data函數(shù),然后返回一個(gè)特別的對(duì)象,所以當(dāng)我們修改其中一個(gè)實(shí)例的時(shí)候并不會(huì)對(duì)其他實(shí)例的數(shù)據(jù)產(chǎn)生變化
那么當(dāng)data不是一個(gè)函數(shù)呢 ,我們簡單改下代碼,代碼如下
function Vue(options) {
this.$data = proxy(options.data)
}
function proxy(options) {
return new Proxy(options, {
get(target, key, value, receiver) {
return Reflect.get(target, key, value, receiver)
},
set(target, key, newValue, receiver) {
Reflect.set(target, key, newValue, receiver)
}
})
}
const data = {
a: 'hello world'
}
const vue1 = new Vue({
data
})
const vue2 = new Vue({
data
})
vue1.$data.a = 'hello Vue'
console.log(vue1.$data.a) // hello Vue
console.log(vue2.$data.a) // hello Vue可以看出,由于共用一個(gè)對(duì)象,當(dāng)代理的時(shí)候也是對(duì)同一個(gè)對(duì)象進(jìn)行代理,那么當(dāng)我們通過一個(gè)實(shí)例去改變數(shù)據(jù)的時(shí)候,就會(huì)影響其他實(shí)例的狀態(tài)
4.如果data必須是一個(gè)對(duì)象呢?
假如有人提出如果data是一個(gè)對(duì)象,那么我們應(yīng)該如何處理呢,其實(shí)也非常簡單,在代理的時(shí)候我們可以將傳入的data對(duì)象通過深拷貝即可,這樣我們就不會(huì)使用相同引用的對(duì)象啦。
[深拷貝封裝參考我以前的文章](不一樣的深拷貝)
總結(jié)
到此這篇關(guān)于Vue的data為何只能是函數(shù)的文章就介紹到這了,更多相關(guān)Vue data為何只能是函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue中后端做Excel導(dǎo)出功能返回?cái)?shù)據(jù)流前端的處理操作
這篇文章主要介紹了vue中后端做Excel導(dǎo)出功能返回?cái)?shù)據(jù)流前端的處理操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
Vue 過渡(動(dòng)畫)transition組件案例詳解
這篇文章主要介紹了Vue 過渡(動(dòng)畫)transition組件案例詳解,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2017-01-01
vue el-table實(shí)現(xiàn)行內(nèi)編輯功能
這篇文章主要為大家詳細(xì)介紹了vue el-table實(shí)現(xiàn)行內(nèi)編輯功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12
vue vue-Router默認(rèn)hash模式修改為history需要做的修改詳解
今天小編就為大家分享一篇vue vue-Router默認(rèn)hash模式修改為history需要做的修改詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09
Vue學(xué)習(xí)筆記進(jìn)階篇之過渡狀態(tài)詳解
本篇文章主要介紹了Vue學(xué)習(xí)筆記進(jìn)階篇之過渡狀態(tài)詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-07-07
vue2使用el-date-picker實(shí)現(xiàn)動(dòng)態(tài)日期范圍demo
這篇文章主要為大家介紹了vue2使用el-date-picker實(shí)現(xiàn)動(dòng)態(tài)日期范圍示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06
解決el-tree節(jié)點(diǎn)過濾不顯示下級(jí)的問題
這篇文章主要介紹了解決el-tree節(jié)點(diǎn)過濾不顯示下級(jí)的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
vue子路由跳轉(zhuǎn)實(shí)現(xiàn)tab選項(xiàng)卡效果
這篇文章主要為大家詳細(xì)介紹了vue子路由跳轉(zhuǎn)實(shí)現(xiàn)tab選項(xiàng)卡效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03

