一、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等改變原數組長度的方法去實現監聽