Object.defineProperty不能监听数组长度变化,而Proxy可以监听?

一、Object.defineProperty

MDN-Configurable中提到:
当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除。默认为 false。

首先对于数组,本身是因为不可监听length,造成了一系列push,pop等这种改变数组长度,无法监听到。

var arr = [1,2,3]
Object.getOwnPropertyDescriptors(arr)

/*
=> {
    0:
        configurable: true
        enumerable: true
        value: 1
        writable: true
        __proto__: Object
    1:
        configurable: true
        enumerable: true
        value: 2
        writable: true
        __proto__: Object
    2:
        configurable: true
        enumerable: true
        value: 3
        writable: true
        __proto__: Object
    length:
        configurable: false
        enumerable: false
        value: 3
        writable: true
        __proto__: Object
}
*/

这里可以明确的看到length 属性的configurable是false,然后各大浏览器厂商包括JS本身,也不允许将length的configurable修改为true,修改后会抛出VM305:1 Uncaught TypeError: Cannot redefine property: length的错误,所以造成了pop,push这种会修改原数组长度的值都无法被监听到

而对于下面这种是可以的

var obj = {},
    temp = 1
Objcet.defineProperty(obj,'list',{
  set:function(value){
    console.log("setted");
    value = 1;
  },
  get:function(){
    return temp;
  }
});
obj.list = []; // setted
obj.list = [1,2,3]; // setted

因为这种是将一个新数组赋给obj.list, 而不是修改原数组

二、Proxy

MDN-Proxy中提到:
target
  代理虚拟化的对象。它通常用作代理的存储后端。根据目标验证关于对象不可扩展性或不可配置属性的不变量(保持不变的语义)。

Array.length 就是不可配置的属性,故Proxy可以监听原数组中长度的变化。

三、Vue3

// vue3 使用

const reactive = new Proxy([1,2,3], handlers) // handlers 为内置getter、setter、has等函数

const arr = reactive([1,2,3]);

通过reactive函数, 将[1,2,3]包装成响应式对象,即Proxy对象,所以你可以通过push,pop等改变原数组长度的方法去实现监听

你可能感兴趣的:(Object.defineProperty不能监听数组长度变化,而Proxy可以监听?)