最近,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方法时都将调用回调函数在页面中输出修改后的属性值。