vue2采用defineProperty定义响应式对象 不支持IE8以下
vue3采用proxy定义响应式对象 es6新语法 不支持IE
proxy相较于defineProperty有如下优点。
Proxy是对整个对象的代理,而Object.defineProperty只能代理某个属性。
对象上新增属性,Proxy可以监听到,Object.defineProperty不能。
数组新增修改,Proxy可以监听到,Object.defineProperty不能。
若对象内部属性要全部递归代理,Proxy可以只在调用的时候递归,而Object.definePropery需要一次完成所有递归,性能比Proxy差。
Proxy不兼容IE,Object.defineProperty不兼容IE8及以下
Proxy使用上比Object.defineProperty方便多。
思考:因此vue2 当对对象的属性进行新增的时候,需要使用vue.set对新增对象进行响应式的设置,而vue3就不用。
vue3里面
数组被替换emptyArray.value = [],常规写法,这样可以检测到变化
watch(emptyArray, () => {//这里使用emptyArray.value是监测不到被替换的console.log('空数组长度变化了')})
使用数组的变更方法(emptyArray.value.push(1)),
watch(emptyArray, () => {//必须使用deep才能检测到使用数组变化变更方法的改变,但是这些改变可以引起UI的改变console.log('空数组长度变化了')},{
deep:true})
总结:ref数组地址变化的时候,才会被监听到。
因为vue3源码里dowatch方法,比较新值与旧值是否相同的时候采用的是object.is
Object.defineProperty(Object, 'is', {
value: function(x, y) {
if (x === y) {
// 针对+0 不等于 -0的情况
return x !== 0 || 1 / x === 1 / y;
}
// 针对NaN的情况
return x !== x && y !== y;
},
configurable: true,
enumerable: false,
writable: true
});
Object.is比较引用类型的时候,比较的是地址。
所以ref的array需要采用=赋值的方式改变其地址,让watch再不需要deep的时候被监听到。