最近,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方法。函數
目前(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以上)版本的瀏覽器中)
能夠監視到的事件並不侷限於以上所述的幾種,能夠自定義監視事件。
可使用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方法時都將調用回調函數在頁面中輸出修改後的屬性值。