vue.js關(guān)于Object.defineProperty的利用原理

其實vue.js作者在這里的時候聊到了原理,也就是關(guān)于視圖和數(shù)據(jù)動態(tài)變化的原因。 如何追蹤變化。
但是還是需要一些基礎(chǔ)知識,關(guān)于ES5的Object.defineProperty().

關(guān)于Object.defineProperty

這個函數(shù)接受三個參數(shù),一個參數(shù)是obj,表示要定義屬性的對象,一個參數(shù)是prop,是要定義或者更改的屬性名字,另外是descriptor,描述符,來定義屬性的具體描述。
Object.defineProperty(obj, prop, descriptor)

下面的是實例代碼,obj是一個沒有屬性的空對象,然后"key"是屬性名,{}大括號里面定義了要給屬性賦值的情況,value代表屬性的值,proto代表繼承屬性的性質(zhì),這里面還有其他的選項。比如configurable,enumerable,writable等默認(rèn)是false的。

// using __proto__
var obj = {};
Object.defineProperty(obj, 'key', {
  __proto__: null, // no inherited properties
  value: 'static'  // not enumerable
                   // not configurable
                   // not writable
                   // as defaults
});

我們通過控制臺的結(jié)果來感受一下writable為false的作用。我們發(fā)現(xiàn),就算對"key"屬性重新賦值了,它的屬性仍然保持不變。

控制臺結(jié)果

descriptors(描述符)分成兩種,一種是data descriptors,另外一種是 accessor descriptors.兩種的descriptors有兩個必選項,configurable和enumerable

configurable
true if and only if the type of this property descriptor may be changed and if the property may be deleted from the corresponding object.Defaults to false
.

代表這個屬性的descriptor也就是描述是可以更改的,這個熟悉也能從對象上面刪除,默認(rèn)false,也就是不能更改跟屬性有關(guān)的任意值,如果我重新對這個屬性進行定義的話,會提示出錯,同時也不能刪除。

configurable

enumerable
true if and only if this property shows up during enumeration of the properties on the corresponding object.Defaults to false
.

代表這個屬性能夠通過for in或者Object.keys
來遍歷。默認(rèn)為false

關(guān)于enumerable的屬性

A data descriptor有兩個可選項.

value
The value associated with the property. Can be any valid JavaScript value (number, object, function, etc).Defaults to undefined
.

這個選項為屬性賦值,可以是任意的JavaScript值,默認(rèn)為undefined

writable
true if and only if the value associated with the property may be changed with an assignment operator.Defaults to false
.

writable表示能不能夠重寫屬性值,默認(rèn)為false

accessor descriptor也有兩個關(guān)鍵的屬性。

get
A function which serves as a getter for the property, or undefined
if there is no getter. The function return will be used as the value of property.Defaults to undefined
.

set

定義了一個函數(shù),作為屬性的getter,如果沒有g(shù)etter就為undefined 默認(rèn)為undefined

set
A function which serves as a setter for the property, or undefined
if there is no setter. The function will receive as only argument the new value being assigned to the property.Defaults to undefined
.

同get

這里面有一點是,可能會從原型鏈上面繼承相應(yīng)的屬性,如果想避免這種情況,可以寫get。所以可以用__proto__: null

下面是一個可愛的例子

var o = {}; // Creates a new object 創(chuàng)造對象

// Example of an object property added with defineProperty with a data property descriptor
Object.defineProperty(o, 'a', {
  value: 37,
  writable: true,
  enumerable: true,
  configurable: true
});
// 'a' property exists in the o object and its value is 37 

// Example of an object property added with defineProperty with an accessor property descriptor
var bValue = 38;
Object.defineProperty(o, 'b', {
  get: function() { return bValue; },
  set: function(newValue) { bValue = newValue; },
  enumerable: true,
  configurable: true
});
o.b; // 38
// 'b' property exists in the o object and its value is 38
// The value of o.b is now always identical to bValue, unless o.b is redefined

// You cannot try to mix both:
Object.defineProperty(o, 'conflict', {
  value: 0x9f91102,
  get: function() { return 0xdeadbeef; }
});
// throws a TypeError: value appears only in data descriptors, get appears only in accessor descriptors

執(zhí)行結(jié)果

第一段代表定義了一個data descriptor,第二段代表定義了accessor descriptor,通get定義了取值操作,第三段代碼告訴我們這兩種不能混用。

視圖和數(shù)據(jù)變化綁定

而vue.js主要利用了accessor descriptors的set和get來更新視圖,這里看到的這個例子挺好,是一個簡單的綁定。
對于一個html頁面

<div>
    <p>你好,<span id='nickName'></span></p>
    <div id="introduce"></div>
</div>    

設(shè)置一個數(shù)據(jù)的屬性的getter和setter

//視圖控制器
var userInfo = {};
Object.defineProperty(userInfo, "nickName", {
    get: function(){
        return document.getElementById('nickName').innerHTML;
    },
    set: function(nick){
        document.getElementById('nickName').innerHTML = nick;
    }
});
Object.defineProperty(userInfo, "introduce", {
    get: function(){
        return document.getElementById('introduce').innerHTML;
    },
    set: function(introduce){
        document.getElementById('introduce').innerHTML = introduce;
    }
})

然后就能愉快地綁定數(shù)據(jù)交互了。

userInfo.nickName = "xxx";
userInfo.introduce = "我是xxx,我來自云南,..."

vue.js的數(shù)據(jù)變動

但是,這個例子只是數(shù)據(jù)和dom節(jié)點的綁定,而vue.js更為復(fù)雜一點,它在網(wǎng)頁dom和accessor之間會有兩層,一層是Wacher,一層是Directive,比如以下代碼。

var a = { b: 1 }
var vm = new Vue({ 
  data: data
})

把一個普通對象(a={b:1})傳給 Vue 實例作為它的 data 選項,Vue.js 將遍歷它的屬性,用Object.defineProperty 將它們轉(zhuǎn)為 getter/setter,如圖綠色的部分所示。
每次用戶更改data里的數(shù)據(jù)的時候,比如a.b =1,setter就會重新通知Watcher進行變動,Watcher再通知Directive對dom節(jié)點進行更改。

官網(wǎng)圖片

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容