一文帶你簡(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' } })
這種寫(xiě)法是可以的,前面提過(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)致的,這在開(kāi)放中是非常不友好的,開(kāi)發(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)文章
vue中后端做Excel導(dǎo)出功能返回?cái)?shù)據(jù)流前端的處理操作
這篇文章主要介紹了vue中后端做Excel導(dǎo)出功能返回?cái)?shù)據(jù)流前端的處理操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09Vue 過(guò)渡(動(dòng)畫(huà))transition組件案例詳解
這篇文章主要介紹了Vue 過(guò)渡(動(dòng)畫(huà))transition組件案例詳解,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2017-01-01vue el-table實(shí)現(xiàn)行內(nèi)編輯功能
這篇文章主要為大家詳細(xì)介紹了vue el-table實(shí)現(xiàn)行內(nèi)編輯功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12vue vue-Router默認(rèn)hash模式修改為history需要做的修改詳解
今天小編就為大家分享一篇vue vue-Router默認(rèn)hash模式修改為history需要做的修改詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09Vue學(xué)習(xí)筆記進(jìn)階篇之過(guò)渡狀態(tài)詳解
本篇文章主要介紹了Vue學(xué)習(xí)筆記進(jìn)階篇之過(guò)渡狀態(tài)詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-07-07vue2使用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)過(guò)濾不顯示下級(jí)的問(wèn)題
這篇文章主要介紹了解決el-tree節(jié)點(diǎn)過(guò)濾不顯示下級(jí)的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04vue子路由跳轉(zhuǎn)實(shí)現(xiàn)tab選項(xiàng)卡效果
這篇文章主要為大家詳細(xì)介紹了vue子路由跳轉(zhuǎn)實(shí)現(xiàn)tab選項(xiàng)卡效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03