OK!既然知道了原理,我们就可以进一步了解为什么出现了之前数组的问题了!
变化检测问题
收到现代JavaScript浏览器的限制,其实主要是 Object.observe() 方法支持的不好,Vue不能检测到对象的添加或者删除。然而Vue在初始化实例时就对属性执行了setter/getter转化过程,所以属性必须开始就在对象上,这样才能让Vue转化它。
所以对于前面的例子就不能理解了 --- 数组中index都可以看做是属性,当我们添加属性并赋值时,Vue并不能检测到对象中属性的添加或者删除,但是其的确是添加或删除了,故我们可以通过console看到变化,所以就没有办法做到响应式; 而在第二个例子中,我们是在已有的属性的基础上进行修改的,这些属性是在最开始就被Vue初始化实例时执行了setter/getter的转化过程,所以说他们的修改是有效的,model的数据可以实时的在view层中得到相应。
补充知识: 什么是 Object.observe() ?
在介绍之前,不得不残忍的说,尽管这个方法可以在某些浏览器上运行,但事实是这个方法已经废弃!
概述: 此方法用于异步地监视一个对象的修改。当对象的属性被修改时,方法的回调函数会提供一个有序的修改流,然而这个接口已经从各大浏览器移除,可以使用通用的proxy 对象。
方法:
Object.observe(obj, callback[, acceptList])
其中obj就是被监控的对象, callback是一个回调函数,其中的参数包括changes和acceptList,
changes一个数组,其中包含的每一个对象代表一个修改行为。每个修改行为的对象包含:
- name: 被修改的属性名称。
- object: 修改后该对象的值。
- type: 表示对该对象做了何种类型的修改,可能的值为"add", "update", or "delete"。
- oldValue: 对象修改前的值。该值只在"update"与"delete"有效。
acceptList在给定对象上给定回调中要监视的变化类型列表。如果省略, ["add", "update", "delete", "reconfigure", "setPrototype", "preventExtensions"] 将会被使用。
var obj = { foo: 0, bar: 1 }; Object.observe(obj, function(changes) { console.log(changes); }); obj.baz = 2; // [{name: 'baz', object: <obj>, type: 'add'}] obj.foo = 'hello'; // [{name: 'foo', object: <obj>, type: 'update', oldValue: 0}] delete obj.baz; // [{name: 'baz', object: <obj>, type: 'delete', oldValue: 2}]
如上所示: 但是chrome也是不支持的,浏览器的兼容性如下:
参考文档: Object.ovserve()
推荐阅读文章: Object.observe() 引爆数据绑定革命