Vue的data為啥只能是函數(shù)原理詳解
前言
在學(xué)習(xí)vue的時(shí)候vue2只有在組件中嚴(yán)格要求data必須是一個(gè)函數(shù),而在普通vue實(shí)例中,data可以是一個(gè)對象,但是在vue3出現(xiàn)后data必須一個(gè)函數(shù),當(dāng)時(shí)看著官方文檔說的是好像是對象的引用問題,但是內(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ù) 下面直接拋錯
2.vue中的data
var app = new Vue({
el: '#app',
data: { a: 'hello world' }
})
這種寫法是可以的,前面提過普通實(shí)例data可以是對象,但是在組件中必須是函數(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
})
這樣在頁面中會顯示2個(gè)內(nèi)容為hello world的div標(biāo)簽 那么當(dāng)我們通過實(shí)例去改變messag呢?
vue1.message = 'hello Vue'

奇怪的事情發(fā)生了,我知識改變了vue1的實(shí)例中的數(shù)據(jù),但是其他實(shí)例的數(shù)據(jù)也發(fā)生了改變,相信很簡單就能看出來這應(yīng)該是共用同一個(gè)對象的引用而導(dǎo)致的,這在開放中是非常不友好的,開發(fā)者很容易就產(chǎn)生連串的錯誤,vue2也知道這種缺陷只是沒有在普通實(shí)例中去體現(xiàn)而已,只在組件中實(shí)現(xiàn)了對于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í)例之前,對于data到底做了什么事情簡單來說就是:
vue 在創(chuàng)建實(shí)例的過程中調(diào)用data函數(shù)返回實(shí)例對象通過響應(yīng)式包裝后存儲在實(shí)例的data上并且實(shí)例可以直接越過data上并且實(shí)例可以直接越過data上并且實(shí)例可以直接越過data訪問屬性
1.通過這句描述可以知道Vue是一個(gè)構(gòu)造函數(shù),并且傳入的參數(shù)中有一個(gè)data的屬性,我們可以$data去訪問,也可以直接訪問這個(gè)屬性,并且我們需要對這個(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è)特別的對象,所以當(dāng)我們修改其中一個(gè)實(shí)例的時(shí)候并不會對其他實(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è)對象,當(dāng)代理的時(shí)候也是對同一個(gè)對象進(jìn)行代理,那么當(dāng)我們通過一個(gè)實(shí)例去改變數(shù)據(jù)的時(shí)候,就會影響其他實(shí)例的狀態(tài)
4.如果data必須是一個(gè)對象呢?
假如有人提出如果data是一個(gè)對象,那么我們應(yīng)該如何處理呢,其實(shí)也非常簡單,在代理的時(shí)候我們可以將傳入的data對象通過深拷貝即可,這樣我們就不會使用相同引用的對象啦。
[深拷貝封裝參考]不一樣的深拷貝
以上就是Vue的data為啥只能是函數(shù)原理詳解的詳細(xì)內(nèi)容,更多關(guān)于Vue data 函數(shù)原理的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Vue2.0利用 v-model 實(shí)現(xiàn)組件props雙向綁定的優(yōu)美解決方案
本篇文章主要介紹了Vue2 利用 v-model 實(shí)現(xiàn)組件props雙向綁定的優(yōu)美解決方案,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-03-03
vue大型項(xiàng)目之分模塊運(yùn)行/打包的實(shí)現(xiàn)
這篇文章主要介紹了vue大型項(xiàng)目之分模塊運(yùn)行/打包的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
vue.js動態(tài)設(shè)置VueComponent高度遇到的問題及解決
這篇文章主要介紹了vue.js動態(tài)設(shè)置VueComponent高度遇到的問題及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-08-08
vue-virtual-scroll-list虛擬組件實(shí)現(xiàn)思路詳解
這篇文章主要給大家介紹了關(guān)于vue-virtual-scroll-list虛擬組件實(shí)現(xiàn)思路的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2023-02-02
uniapp中使用lottie實(shí)現(xiàn)JSON動畫的操作步驟
這篇文章主要介紹了如何在項(xiàng)目中使用JSON動畫組件,包括創(chuàng)建目錄結(jié)構(gòu)、下載JSON文件、編寫自定義組件代碼以及組件的使用方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2025-01-01
vue中使用h5 video標(biāo)簽實(shí)現(xiàn)彈窗播放本地視頻的方法
本文主要介紹了vue中使用h5 video標(biāo)簽實(shí)現(xiàn)彈窗播放本地視頻的方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
vue中jsencrypt與base64加密解密的實(shí)用流程
vue項(xiàng)目里面使用到的加密和解密的方法,本文主要介紹了vue中jsencrypt與base64加密解密的實(shí)用流程,具有一定的參考價(jià)值,感興趣的可以了解一下2023-10-10
前端單獨(dú)實(shí)現(xiàn)vue動態(tài)路由的示例代碼
Vue動態(tài)路由權(quán)限涉及根據(jù)用戶權(quán)限動態(tài)生成路由配置,實(shí)現(xiàn)此功能可增強(qiáng)應(yīng)用安全性、靈活性,提升用戶體驗(yàn)和開發(fā)效率,本文就來介紹一下前端單獨(dú)實(shí)現(xiàn)vue動態(tài)路由的示例代碼,感興趣的可以了解一下2024-09-09

