日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > vue >内容正文

vue

Vue(ES6)中的data属性为什么不能是一个对象?

發布時間:2023/12/2 vue 54 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Vue(ES6)中的data属性为什么不能是一个对象? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

以下引官網原文:當一個組件被定義,data 必須聲明為返回一個初始數據對象的函數,因為組件可能被用來創建多個實例。如果 data 仍然是一個純粹的對象,則所有的實例將共享引用同一個數據對象!通過提供 data 函數,每次創建一個新實例后,我們能夠調用 data 函數,從而返回初始數據的一個全新副本數據對象。

最近來面試的很多人。我都會問這個問題“vue中,為什么data是一個方法返回一個對象,而不是直接賦給一個對象”,只有少數人會回答出是怕重復創建實例造成多實例共享一個數據對象。更多的人回答是不知道,或者是官方文檔要求這么寫就這么寫了。

其實這個問題的考點無非就是對vue的熟悉情況,挖掘應聘者的自驅學習能力,對技術的求知欲。這樣的人往往技術成長快,具備很強的獨立解決問題能力。也是各個技術團隊都喜歡的一種人。

首先在vue的源碼中,有這樣的處理:

// vue/src/core/instance/state.jsfunction initData (vm: Component) {var data = vm.$options.data;data = vm._data = typeof data === 'function'? getData(data, vm): data || {};if (!isPlainObject(data)) {data = {};process.env.NODE_ENV !== 'production' && warn('data functions should return an object:\n' 'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',vm);}...}

顯然,vue是支持將一個對象作為vue構造參數中data屬性的值并且,如果data是方法的話,也會先取得內部返回的對象結果。并且在vuex中又存在這樣的用法:

// vuex/src/store.jsfunction resetStoreVM (store, state, hot) {...const silent = Vue.config.silentVue.config.silent = truestore._vm = new Vue({data: {$$state: state},computed})...}

這是怎么回事呢?既然支持,又不讓我們用,而且當我們在一個vue文件中,直接給一個data賦予一個對象則會引起紅色警告:

[Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions.

這個警告來自于Vue源碼中的vue/src/core/util/options.js

strats.data = function (parentVal: any,childVal: any,vm?: Component): ?Function {if (!vm) {if (childVal && typeof childVal !== 'function') {process.env.NODE_ENV !== 'production' && warn('The "data" option should be a function ' 'that returns a per-instance value in component ' 'definitions.',vm)return parentVal}return mergeDataOrFn(parentVal, childVal)}return mergeDataOrFn(parentVal, childVal, vm)}

首先我們需要了解在vue文件的代碼被實例化成vue組件的過程需要經歷下面這些步驟:

  • vue文件被loader處理,template被編譯成render函數,script被編譯成一個對象變量
  • 將script編譯后的對象傳入render中,并在render函數中調用vue.createElement(來自vue/src/core/vdom/create-element.js)構建vue組件
  • 在createElement中,如果是vue組件的話,通過createComponent(vue/src/core/vdom/create-component.js)構建組件
  • 將script編譯出來的對象變量通過上下文的$options中取出,并使用Vue.extends(vue/src/core/global-api/extend.js)通過該對象構建出一個新的Vue對象
  • 在4中因為使用了mergeOptions,進而觸發了對data的類型驗證,也就顯示了之初的那個警告。

    那么為一個對象的屬性賦予一個對象真的就會造成共享對象么?讓我們看下面的代碼:

    class A {constructor(opt) {this.opt = opt;}update() {this.opt.data.a ;}notify() {console.log(this.opt);}}

    我們用這個類來虛擬化Vue的構造。然后進行測試:

    // testlet c = new A({ data: { a: 1 }});let d = new A({ data: { a: 1 }});c.update();d.update();c.notify(); // Object data: a: 2

    我們通過字面量的方式來為構造參數傳入一個對象屬性,然而我們驚奇的發現,其實并沒有發生共享引用的問題。這是什么鬼?

    哦,不對,我們通常在使用vue的時候是在vue文件中export出一個對象,然后這個對象會在vue-loader的時候被編譯傳入到模版編譯后的render函數中。那么我們換一個方法來做一個實驗:

    // test.js文件,用于虛擬vue文件導出的vue options對象export default {data: {a: 1}}// index.jslet a = new A(test);let b = new A(test);a.update();b.update();a.notify(); // Object data: a: 3

    什么?在這里產生了vue文檔中提到的共享引用的問題。這是為什么呢?

    原因在于vue的編譯過程以及引入的import過程,通過babel編譯,test.js會被轉化為es5語法的js文件:

    var Re = {data: {a: 1}};var Oe = function () {function e(t) {Object(i["a"])(this, e), this.opt = t}return Object(o["a"])(e, [{key: "update",value: function () {this.opt.data.a }}, {key: "notify",value: function () {console.log(this.opt)}}]), e}(),Fe = new Oe(Re),Ne = new Oe(Re);Fe.update(), Ne.update(), Fe.notify();var $e = new Oe({data: {a: 1}}),Ve = new Oe({data: {a: 1}});$e.update(), Ve.update(), $e.notify(),

    What?原來我們的每一個vue文件經過babel編譯,將導出的對象直接替換成了一個對象變量,然后將這個變量傳入到對應的組件構造函數中。因此,也就產生了引用共享的問題(所有js對象皆引用)。

    由于vue源碼并沒有通讀,因此如有錯誤請指教

    總結

    以上是生活随笔為你收集整理的Vue(ES6)中的data属性为什么不能是一个对象?的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。