vue的響應式核心方法 Object.defineProperty詳解

  • 關於vue響應式原理的文章太多了,看了不少,仍是看看mdn的解釋,完全理解一下到底什麼是Object.defineProperty。這個方法具體怎麼用。參數都是什麼。纔會完全理解vue到底怎麼劫持數據而且響應的。

vue2.0的核心方法

Object.defineProperty(obj,prop,descriptor)javascript

vue核心簡說

vue.js採用的是數據劫持++++發佈-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調。那麼Object咱們知道是一個對象,defineProperty()這個方法是什麼呢?做用是什麼呢,我 們來一塊兒分析一下html

mdn文檔解釋Object.definePropertyvue

核心的方法

Object.defineProperty()這個方法包含三個參數,java

  • obj是要在其上定義屬性的對象,簡單說就是你要操做的那個對象api

  • prop要定義或修改屬性的名稱,簡單說就是你要操做的那個對象下的屬性(對象下沒有那個屬性怎麼辦?能夠本身設置的數組

  • descriptor將定義或修改的屬性描述:注意這個不知道就要看api了,他有這幾個屬性bash

descriptor屬性描述符

  1. 對象裏目前存在的屬性描述符有兩種主要形式:數據描述符存取描述符

數據描述符是一個具備值的屬性,該值多是可寫的,也可能不是可寫的。app

存取描述符是由getter-setter函數對描述的屬性。函數

描述符必須是這兩種形式之一;不能同時是二者。測試

  1. 共存關係

(1)數據描述符和存取描述符均具備如下可選鍵值(默認值是在使用Object.defineProperty()定義屬性的狀況下):

configurable 當且僅當該屬性的 configurable 爲 true 時,該屬性描述符纔可以被改變,同時該屬性也能從對應的對象上被刪除。默認爲 false。

enumerable 當且僅當該屬性的enumerable爲true時,該屬性纔可以出如今對象的枚舉屬性中。默認爲 false。

(2)數據描述符同時具備如下可選鍵值:

value 該屬性對應的值。能夠是任何有效的 JavaScript 值(數值,對象,函數等)。默認爲 undefined。

writable 當且僅當該屬性的writable爲true時,value才能被賦值運算符改變。默認爲 false。

(3)存取描述符同時具備如下可選鍵值:(劃重點啊。這是關鍵啊,其實就是函數)

get一個給屬性提供 getter 的方法,若是沒有 getter 則爲 undefined。當訪問該屬性時,該方法會被執行,方法執行時沒有參數傳入,可是會傳入this對象(因爲繼承關係,這裏的this並不必定是定義該屬性的對象)。默認爲 undefined。

set 一個給屬性提供 setter 的方法,若是沒有 setter 則爲 undefined。當屬性值修改時,觸發執行該方法。該方法將接受惟一參數,即該屬性新的參數值。 默認爲 undefined。

上面啥意思呢,意思是說啊,descriptor屬性描述符總共有6個是屬性
configurable
enumerable

value
writable

get
set

可是6個不能同時設置,
不然會報錯。其中共存屬性能夠一直存在。其餘四個兩兩一組。有你沒我。有我沒你的意思

要麼
configurable
enumerable
value
writable

要麼
configurable
enumerable
get
set

複製代碼
  1. 共存屬性和數據描述符號屬性講解
var obj = {
    test:"hello"
}
//對象已有的屬性添加特性描述 若是對象自己有這個屬性,就正好能夠操做了
Object.defineProperty(obj,"test",{
    configurable:true | false,
    enumerable:true | false,
    value:任意類型的值,
    writable:true | false
});
//對象新添加的屬性的特性描述,若是對象沒有這個屬性,就寫上,就至關於添加上這個屬性,也能夠進行操做
Object.defineProperty(obj,"newKey",{
    configurable:true | false,
    enumerable:true | false,
    value:任意類型的值,
    writable:true | false
})
複製代碼

(1) value(數據描述符)

// 屬性對應的值,可使任意類型的值,默認爲undefined

var obj = {}
//第一種狀況:不設置value屬性
Object.defineProperty(obj,"newKey",{
 
});
console.log( obj.newKey );  //undefined
------------------------------
//第二種狀況:設置value屬性
Object.defineProperty(obj,"newKey",{
    value:"hello"
});
console.log( obj.newKey );  //hello
複製代碼

(2) writable(數據描述符)

//屬性的值是否能夠被重寫。設置爲true能夠被重寫;設置爲false,不能被重寫。默認爲false。

var obj = {}
//第一種狀況:writable設置爲false,不能重寫。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false
});
//更改newKey的值
obj.newKey = "change value";
console.log( obj.newKey );  //hello
 
//第二種狀況:writable設置爲true,能夠重寫
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:true
});
//更改newKey的值
obj.newKey = "change value";
console.log( obj.newKey );  //change value
複製代碼

(3)enumerable(共存描述符)

// 此屬性是否能夠被枚舉(使用for...in或Object.keys())。設置爲true能夠被枚舉;設置爲false,不能被枚舉。默認爲false。


var obj = {}
//第一種狀況:enumerable設置爲false,不能被枚舉。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:false
});
 
//枚舉對象的屬性
for( var attr in obj ){
    console.log( attr );  // undefined
}
//----------------------------------------
//第二種狀況:enumerable設置爲true,能夠被枚舉。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:true
});
 
//枚舉對象的屬性
for( var attr in obj ){
    console.log( attr );  //newKey
}
複製代碼

(4)configurable(共存描述符)

//是否能夠刪除目標屬性或是否能夠再次修改屬性的特性(writable, configurable, enumerable)。
//設置爲true能夠被刪除或能夠從新設置特性;設置爲false,不能被能夠被刪除或不能夠從新設置特性。默認爲false。

//這個屬性起到兩個做用:

//1.目標屬性是否可使用delete刪除

//2.目標屬性是否能夠再次設置特性


//-----------------測試目標屬性是否能被刪除------------------------
var obj = {}
//第一種狀況:configurable設置爲false,不能被刪除。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:false,
    configurable:false
});
//刪除屬性
delete obj.newKey;
console.log( obj.newKey ); //hello
 
//第二種狀況:configurable設置爲true,能夠被刪除。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:false,
    configurable:true
});
//刪除屬性
delete obj.newKey;
console.log( obj.newKey ); //undefined
 
//-----------------測試是否能夠再次修改特性------------------------
var obj = {}
//第一種狀況:configurable設置爲false,不能再次修改特性。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:false,
    configurable:false
});
 
//從新修改特性
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:true,
    enumerable:true,
    configurable:true
});
console.log( obj.newKey ); //報錯:Uncaught TypeError: Cannot redefine property: newKey
 
//第二種狀況:configurable設置爲true,能夠再次修改特性。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:false,
    configurable:true
});
 
//從新修改特性
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:true,
    enumerable:true,
    configurable:true
});
console.log( obj.newKey ); //hello
複製代碼
  1. 存取描述符號屬性講解

set是該屬性值被設置時執行的回調函數(默認是undefined)

get是該屬性值被得到時執行的回調函數(默認是undefined)

  1. Vue響應式和雙向綁定的原理

Vue實例在初始化時,遍歷在Observer(觀察者)中全部屬性經過Object.defineProperty()來實現他們的存取描述符(getter和setter),這樣以來給任何對象的任意屬性賦值都會觸發該屬性的setter,那麼就能監聽到數據變化。同時每一個屬性都會設置一個Dep(消息訂閱器),他內部維護了一個數組,用來記錄全部Watcher(訂閱者)。        而後Vue經過Compile(解析器)編譯模板,將模板中的變量替換成對應的數據並渲染頁面視圖。此時Watcher會將本身添加到Dep中,到這裏一個Vue實例的初始化完畢。        當屬性值發生改變時,觸發setter函數,setter會調用Dep.notify()通知每個訂閱該屬性的Watcher,Watcher會調用自身的update()函數對視圖進行更新。這樣一來雙向綁定就實現了。

js 手動實現一個雙向綁定

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>雙向綁定demo</title>
        <meta charset="UTF-8">
    </head>
    <body>
        <div id="app">
            <div>雙向綁定demo</div>
            <input type="text" id="input">
            <div>
				<span>input:</span>
				<span id="output"></span>
			</div>
        </div>
    </body>
    <script> var obj={} Object.defineProperty(obj,'input',{ get:function(){ return obj.input }, set:function(value){ document.getElementById('input').value = value document.getElementById('output').innerHTML = value } }) document.addEventListener('keyup',function(e){ obj.input = e.target.value }) </script>
</html>
複製代碼
相關文章
相關標籤/搜索