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

奇怪的事情發(fā)生了,我知識(shí)改變了vue1的實(shí)例中的數(shù)據(jù),但是其他實(shí)例的數(shù)據(jù)也發(fā)生了改變,相信很簡(jiǎn)單就能看出來(lái)這應(yīng)該是共用同一個(gè)對(duì)象的引用而導(dǎo)致的,這在開放中是非常不友好的,開發(fā)者很容易就產(chǎn)生連串的錯(cuò)誤,vue2也知道這種缺陷只是沒(méi)有在普通實(shí)例中去體現(xiàn)而已,只在組件中實(shí)現(xiàn)了對(duì)于data的約束
為了讓大家更好的立即為啥data必須是一個(gè)函數(shù),黑貓?jiān)诖撕?jiǎn)單實(shí)現(xiàn)一個(gè)vue的實(shí)例然后來(lái)證明為啥data是一個(gè)函數(shù),以及如果data不是一個(gè)函數(shù),我們應(yīng)該如何處理
3.證明data是函數(shù)以及原理實(shí)現(xiàn)
在實(shí)現(xiàn)簡(jiǎn)單原理之前,我們需要搞清楚Vue在創(chuàng)建實(shí)例之前,對(duì)于data到底做了什么事情簡(jiǎn)單來(lái)說(shuō)就是:
vue 在創(chuàng)建實(shí)例的過(guò)程中調(diào)用data函數(shù)返回實(shí)例對(duì)象通過(guò)響應(yīng)式包裝后存儲(chǔ)在實(shí)例的data上并且實(shí)例可以直接越過(guò)data上并且實(shí)例可以直接越過(guò)data上并且實(shí)例可以直接越過(guò)data訪問(wèn)屬性
1.通過(guò)這句描述可以知道Vue是一個(gè)構(gòu)造函數(shù),并且傳入的參數(shù)中有一個(gè)data的屬性,我們可以$data去訪問(wèn),也可以直接訪問(wèn)這個(gè)屬性,并且我們需要對(duì)這個(gè)data做代理
那么簡(jiǎn)單實(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通過(guò)簡(jiǎn)單實(shí)現(xiàn)可與看出來(lái),當(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ù)呢 ,我們簡(jiǎ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 = {
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)我們通過(guò)一個(gè)實(shí)例去改變數(shù)據(jù)的時(shí)候,就會(huì)影響其他實(shí)例的狀態(tài)
4.如果data必須是一個(gè)對(duì)象呢?
假如有人提出如果data是一個(gè)對(duì)象,那么我們應(yīng)該如何處理呢,其實(shí)也非常簡(jiǎn)單,在代理的時(shí)候我們可以將傳入的data對(duì)象通過(guò)深拷貝即可,這樣我們就不會(huì)使用相同引用的對(duì)象啦。
[深拷貝封裝參考我以前的文章](不一樣的深拷貝)
總結(jié)
到此這篇關(guān)于Vue的data為何只能是函數(shù)的文章就介紹到這了,更多相關(guān)Vue data為何只能是函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue3+ts 兄弟組件之間傳值的實(shí)現(xiàn)
Vue3是一款流行的前端框架,它支持多種傳值方式,包括兄弟組件之間的傳值,本文主要介紹了vue3+ts 兄弟組件之間傳值的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11
Nuxt3項(xiàng)目搭建過(guò)程(Nuxt3+element-plus+scss詳細(xì)步驟)
這篇文章主要介紹了Nuxt3項(xiàng)目搭建(Nuxt3+element-plus+scss詳細(xì)步驟),本次記錄一次使用Nuxt3搭建前端項(xiàng)目的過(guò)程,內(nèi)容包含Nuxt3的安裝,基于Vite腳手架(默認(rèn))構(gòu)建的vue3項(xiàng)目,element-plus的安裝配置,scss的安裝,目錄結(jié)構(gòu)的創(chuàng)建和解釋,需要的朋友可以參考下2022-12-12
Ant Design Vue pro 動(dòng)態(tài)路由的實(shí)現(xiàn)和打包方式
這篇文章主要介紹了Ant Design Vue pro 動(dòng)態(tài)路由的實(shí)現(xiàn)和打包方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06
vue開發(fā)中數(shù)據(jù)更新但視圖不刷新的解決方法
在開發(fā)中我們處理數(shù)據(jù)時(shí)會(huì)遇到數(shù)據(jù)更新了,但視圖并沒(méi)有更新,這種情況往往是數(shù)據(jù)嵌套層數(shù)過(guò)多導(dǎo)致的問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于vue開發(fā)中數(shù)據(jù)更新但視圖不刷新的解決方法,需要的朋友可以參考下2022-11-11
詳解Vue + Vuex 如何使用 vm.$nextTick
這篇文章主要介紹了詳解Vue + Vuex 如何使用 vm.$nextTick,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-11-11

