使用Object.observe 實現數據綁定

Object.observe API概述

最近,JavaScript的MVC框架在Web開發屆很是盛行。在實現MVC框架的時候,一個很是重要的技術就是數據綁定技術。若是要實現模型與視圖的分離,就必需要使用數據綁定技術。可是,MVC框架的原做者對於數據綁定處理實現得並不如人意,所以,Google公司在ECMAScript中封裝了一個Object.observe API,專用於實現數據綁定處理(目前將其正式使用在V8中)。html

Object.observe API能夠被稱爲一種「能夠對任何對象的屬性值修改進行監視的事件處理函數」。chrome

在Firefox瀏覽器中,實現了與之相相似的能夠對DOM對象進行觀察的Mutation觀察器數組

目前爲止,Object.observe API已經被strawman proposal所認可,被正式使用在V8中。自11月末開始,已經能夠在Chrome Canary與開發者通道中對其進行啓用。瀏覽器

本文介紹Object.observe API中的基本功能及一些代碼示例。ruby

目前爲止,Object.observe API中包括以下所示的四個方法:app

  • Object.observe:爲對象指定監視時調用的回調函數
  • Object.unobserve:移除監視時調用的回調函數
  • Object.deliverChangeRecords:經過回調函數對對象值進行修改
  • Object.getNotifier:獲取Notifier對象

能夠觀察到的屬性操做包括如下幾種:框架

  • new:添加屬性
  • updated:修改屬性值
  • reconfigured:修改屬性設定
  • deleted:刪除屬性

接下來介紹如何使用Object.observe方法。函數

目前(2012年12月6日)爲止,若是要使用Object.observe API,須要使用Chrome Canary或Chrome Dev Channel(25.0.1337.0 dev-m以上)版本的瀏覽器,同時在chrome://flags/中啓用「啓用實驗性 JavaScript」選項,以下圖所示。this

簡單代碼示例

Object.observe方法用於爲對象指定監視到屬性修改時調用的回調函數,使用方法以下所示。3d

Object.observe(obj, callback);

Object.observe方法中使用兩個參數,其中第一個參數值爲須要被監視的對象,第二個參數值爲監視到屬性修改時調用的回調函數名。能夠將各對象的屬性操做時生成的ChangeRecord對象數組設置爲回調函數的參數。

ChangeRecord對象擁有type、name、oldValue、object四個屬性,各屬性含義以下所示。

function callback(changes) {
    changes.forEach(function(change) {
        console.log(change.type);     //對屬性進行了什麼操做 new/updated/reconfigured/delted
        console.log(change.name);     //屬性名
        console.log(change.oldValue); //修改以前的屬性值
        console.log(change.object);   //被監視的對象
    });
}

使用以下所示的代碼,能夠在任什麼時候刻對於對象屬性的上述四種操做(new/updated/reconfigured/delted)進行監視:

var obj = {a: 1};
    Object.observe(obj, output); //爲對象指定監視時調用的回調函數

    obj.b = 2; //添加屬性
    obj.a = 2; //修改屬性值
    Object.defineProperties(obj, {a: { enumerable: false}}); //修改屬性設定
    delete obj.b; //刪除屬性  
    function output(change) {
        //回調函數,能夠在此處書寫在頁面上的輸出。
    }

頁面運行結果以下圖所示(在Chrome Canary或Chrome Dev Channel(25.0.1337.0 dev-m以上)版本的瀏覽器中)

建立自定義Notify對象

能夠監視到的事件並不侷限於以上所述的幾種,能夠自定義監視事件。

可使用Notifier對象來自定義針對對象的可訪問屬性(可以使用getter方法或setter方法讀取或設置的屬性)被修改時所觸發的事件。這時,咱們須要Object.getNotifier()方法獲取被監視對象的Notifier對象,並使用notify方法進行屬性被修改的通知。

在如下這個示例代碼中,爲對象自定義time_updated事件及time_read事件並利用這兩個事件監視對象的私有屬性_time的讀取及修改。

var obj2 = {_time: new Date(0)};
var notifier = Object.getNotifier(obj2); //獲取Notifier對象
Object.defineProperties(obj2, { //設置對象的可訪問屬性 
    _time: {
        enumerable: false,
        configrable: false
    },
    seen: {
        set: function(val) {
            var notifier = Object.getNotifier(this);
            notifier.notify({
                type: 'time_updated', //定義time_updated事件
                name: 'seen',
                oldValue: this._time
            });
            this._time = val;
        },
        get: function() {
            var notifier = Object.getNotifier(this);
            notifier.notify({
                type: 'time_read', //定義time_read事件
                name: 'seen',
                oldValue: this._time
            });
            return this._time;
        }
    }
});
Object.observe(obj2, output); //爲對象指定監視時調用的回調函數
//執行屬性操做
var first_time = obj2.seen; //觸發time_read事件
obj2.seen = new Date();      //觸發time_updated事件
var second_time = obj2.seen; //觸發time_read事件

控制回調函數的執行時間

在默認狀況下,使用Object.observe API指定的回調函數將在JavaScript腳本代碼執行結束時被調用。所以若是對同一對象的同一屬性執行了屢次操做,回調函數中獲取到的各屬性值爲最後一個操做結束後的值。將前面這個示例中的代碼稍做修改,對使用Object.observe API進行監視的對象的屬性值連續修改七次(爲了不回調函數的循環調用刪除對time_read事件的監視)。

obj3.seen = new Date(2013, 0, 1, 0, 0, 0); //觸發time_updated事件
  obj3.seen = new Date(2013, 0, 2, 0, 0, 0); //觸發time_updated事件
  obj3.seen = new Date(2013, 0, 3, 0, 0, 0); //觸發time_updated事件
  obj3.seen = new Date(2013, 0, 4, 0, 0, 0); //觸發time_updated事件
  obj3.seen = new Date(2013, 0, 5, 0, 0, 0); //觸發time_updated事件
  obj3.seen = new Date(2013, 0, 6, 0, 0, 0); //觸發time_updated事件
  obj3.seen = new Date(2013, 0, 7, 0, 0, 0); //觸發time_updated事件
    

頁面運行結果以下圖所示(在Chrome Canary或Chrome Dev Channel(25.0.1337.0 dev-m以上)版本的瀏覽器中)

從這個結果中咱們能夠看出,在回調函數中獲取到的屬性值爲同一個屬性值(2013年1月7日)。爲了強制獲取事件觸發後當即設置的屬性值,咱們須要使用Object.deliverChangeRecords方法。

在以下所示的代碼中,每次修改了屬性值後,即調用Object.deliverChangeRecords方法當即調用回調函數。

obj4.seen = new Date(2013, 0, 1, 0, 0, 0); //觸發time_updated事件
  Object.deliverChangeRecords(output);       //調用回調函數
  obj4.seen = new Date(2013, 0, 2, 0, 0, 0); //觸發time_updated事件
  Object.deliverChangeRecords(output);       //調用回調函數
  obj4.seen = new Date(2013, 0, 3, 0, 0, 0); //觸發time_updated事件
  Object.deliverChangeRecords(output);       //調用回調函數
  obj4.seen = new Date(2013, 0, 4, 0, 0, 0); //觸發time_updated事件
  Object.deliverChangeRecords(output);       //調用回調函數
  obj4.seen = new Date(2013, 0, 5, 0, 0, 0); //觸發time_updated事件
  Object.deliverChangeRecords(output);       //調用回調函數
  obj4.seen = new Date(2013, 0, 6, 0, 0, 0); //觸發time_updated事件
  Object.deliverChangeRecords(output);       //調用回調函數
  obj4.seen = new Date(2013, 0, 7, 0, 0, 0); //觸發time_updated事件

頁面運行結果以下圖所示(在Chrome Canary或Chrome Dev Channel(25.0.1337.0 dev-m以上)版本的瀏覽器中)

從這個結果中咱們能夠看出,每次執行Object.deliverChangeRecords方法時都將調用回調函數在頁面中輸出修改後的屬性值。

相關文章
相關標籤/搜索