17: VUE數據綁定 與 Object.defineProperty

  VUE數據綁定原理:https://segmentfault.com/a/1190000006599500?utm_source=tag-newestvue

  Object.defineProperty():https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/definePropertysegmentfault

                                        http://www.javashuo.com/article/p-qasukviu-dp.html數組

1.1 Object.defineProperty()介紹

  一、defineProperty做用app

      1. Object.defineProperty() 方法會直接在一個對象上定義一個新屬性,或者修改一個對象的現有屬性, 並返回這個對象。mvvm

  二、語法:Object.defineProperty(obj, prop, descriptor)ide

    1)參數說明:函數

        obj: 必需。目標對象
        prop: 必需。需定義或修改的屬性的名字
        descriptor: 必需。目標屬性所擁有的特性ui

    2)返回值:this

        傳入函數的對象。即第一個參數objspa

  三、數據描述:

     做用:當修改或定義對象的某個屬性的時候,給這個屬性添加一些特性

    1)設置的特性總結

 

        value:    設置屬性的值

        writable:    值是否能夠重寫。true | false

        enumerable:    目標屬性是否能夠被枚舉。true | false

        configurable:    目標屬性是否能夠被刪除或是否能夠再次修改特性 true | false

//一、任意建立一個對象obj
var obj = {
    test:"hello"
}
// 原始值 obj = {test: "hello"}


//二、修改obj "test"值爲"test的新值"
Object.defineProperty(obj,"test",{
    configurable:true | false,
    enumerable:true | false,
    value:'test的新值',
    writable:true | false
});
// 修改後 obj = {test: "test的新值"}


//三、對象新添加的屬性的特性描述
Object.defineProperty(obj,"newKey",{
    configurable:true | false,
    enumerable:true | false,
    value:"newValue",
    writable:true | false
});
// 修改後 obj = {test: "test的新值", newKey: "newValue"}
使用defineProperty修改對象的值/添加新值

  四、屬性:value(對象新值)

//一、定義一個空對象obj
var obj = {}

//二、爲新對象設置一個值 newKey : hello
Object.defineProperty(obj,"newKey",{
    value:"hello"
});
console.log( obj.newKey );  //hello
屬性:value

  五、屬性: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定義值是否能夠被重寫

  六、屬性:enumerable

     說明:設置爲true能夠被枚舉;設置爲false,不能被枚舉。默認爲false。 

var obj = {}

//一、enumerable設置爲true,能夠被枚舉。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:true
});

//二、枚舉對象的屬性
for( var attr in obj ){
    console.log( attr );  //newKey
}
enumerable設置爲可枚舉類型

  七、屬性:configurable

    1)做用

        1. 目標屬性是否可使用delete刪除,目標屬性是否能夠再次設置特性

        2. 設置爲true能夠被刪除或能夠從新設置特性;設置爲false,不能被能夠被刪除或不能夠從新設置特性。默認爲false。

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 設置是否能被刪除、修改

  八、getter/setter

      1. getter 是一種得到屬性值的方法,setter是一種設置屬性值的方法。

      2. 當使用了getter或setter方法,不容許使用writable和value這兩個屬性

      3. get或set不是必須成對出現,任寫其一就能夠,若是不設置方法,則get和set的默認值爲undefined

var obj = {};
var initValue = 'hello';

Object.defineProperty(obj,"newKey",{
    get:function (){
        return initValue;            //當獲取值的時候觸發的函數
    },
    set:function (value){
        initValue = value;        //當設置值的時候觸發的函數,設置的新值經過參數value拿到
    }
});

//獲取值
console.log( obj.newKey );  //hello

//設置值
obj.newKey = 'change value';

console.log( obj.newKey ); //change value

 1.2 vue實現數據綁定原理

    參考博客:https://segmentfault.com/a/1190000006599500?utm_source=tag-newest

  一、vue使用數據劫持實現數據雙向綁定

      1. vue.js 採用數據劫持結合發佈者-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter,getter

      2. 在數據變更時發佈消息給訂閱者,觸發相應的監聽回調。

  二、數據劫持原理

      一、實現一個數據監聽器Observer,可以對數據對象的全部屬性進行監聽,若有變更可拿到最新值並通知訂閱者

      二、實現一個指令解析器Compile,對每一個元素節點的指令進行掃描和解析,根據指令模板替換數據,以及綁定相應的更新函數

      三、實現一個Watcher,做爲鏈接Observer和Compile的橋樑,可以訂閱並收到每一個屬性變更的通知,執行指令綁定的相應回調函數,從而更新視圖

      四、mvvm入口函數,整合以上三者

      

  三、第一步:實現Observer

      1. 咱們知道能夠利用Obeject.defineProperty()來監聽屬性變更

      2. 那麼將須要observe的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter和getter

      3. 這樣的話,給這個對象的某個值賦值,就會觸發setter,那麼就能監聽到了數據變化。

var data = {name: 'kindeng'};
observe(data);
data.name = 'dmq'; // 哈哈哈,監聽到值變化了 kindeng --> dmq

function observe(data) {
    if (!data || typeof data !== 'object') {
        return;
    }
    // 取出全部屬性遍歷
    Object.keys(data).forEach(function(key) {
        defineReactive(data, key, data[key]);
    });
};

function defineReactive(data, key, val) {
    observe(val); // 監聽子屬性
    Object.defineProperty(data, key, {
        enumerable: true, // 可枚舉
        configurable: false, // 不能再define
        get: function() {
            return val;
        },
        set: function(newVal) {
            console.log('哈哈哈,監聽到值變化了 ', val, ' --> ', newVal);
            val = newVal;
        }
    });
}
Observer 給對象添加setter、getter屬性

      4. 這樣咱們已經能夠監聽每一個數據的變化了,那麼監聽到變化以後就是怎麼通知訂閱者了,因此接下來咱們須要實現一個消息訂閱器

      5. 很簡單維護一個數組,用來收集訂閱者,數據變更觸發notify,再調用訂閱者的update方法

/ ... 省略
function defineReactive(data, key, val) {
    var dep = new Dep();
    observe(val); // 監聽子屬性

    Object.defineProperty(data, key, {
        // ... 省略
        set: function(newVal) {
            if (val === newVal) return;
            console.log('哈哈哈,監聽到值變化了 ', val, ' --> ', newVal);
            val = newVal;
            dep.notify(); // 通知全部訂閱者
        }
    });
}

function Dep() {
    this.subs = [];
}
Dep.prototype = {
    addSub: function(sub) {
        this.subs.push(sub);
    },
    notify: function() {
        this.subs.forEach(function(sub) {
            sub.update();
        });
    }
};
數據變化觸發notify調用訂閱者的update方法

 

 

 

 

 

 

 

11111111111111111

相關文章
相關標籤/搜索