监测属性变化的有 defineProperty 和 proxy。
但两者使用和局限并不一样。
- defineProperty可以监测对象修改属性或者获取属性,但不能检测对象增加或删除属性,而且也不能检测数组
- proxy可以监测对象或数组,增删改查属性,但兼容性不好。
- 用法也不一样:proxy里操作的是对象。defineProperty操作的是一个变量值。这点特别注意。
之前写过defineProperty,这里不再赘述,下面简单说下proxy
。
proxy
字面意思代理,有点像秘书,想要约总经理,秘书都会先挡着。阮一峰大大的proxy官方解释。
js可以Proxy
类创建proxy实例
,每个实例就是某个对象的秘书。针对增删改查对象属性的操作,秘书都可以做些小动作。
!!!注意,这里的对象包含数组。
!!!注意,这里的对象包含数组。
!!!注意,这里的对象包含数组。
怎么拦截对象增删改查属性
没啥悬念,直接上demo。
改查
// 比如,obj就是我
let obj = { name: "颜酱", age: 18, phone: 18362780848 };
// 给我加个秘书
let proxy = new Proxy(obj, {
// 想要知道我的其他信息,先问问秘书,秘书心情好就说
get(target, key) {
// target就是obj,key就是访问的属性
const isHappy = Math.random() > 0.5;
return isHappy ? target[key] : "不太清楚";
},
// 想更新我的信息,同样看我秘书心情
set(target, key, value) {
// target就是obj,key就是访问的属性,value是别人想要的属性值
const isHappy = Math.random() > 0.5;
// 心情好就更新,不好就不改了
isHappy ? (target[key] = value) : console.log("修改失败");
}
});
// 这里注意,只能使用秘书,只有秘书才会说或者不说,如果直接obj.name跟秘书就没关系了
console.log(proxy.name);
// 同理,这里不能 obj.phone = 28
proxy.phone = 18362790909;
// 一旦修改成功,obj.phone就会被更新,当然不成功肯定不会被更新
console.log(proxy, obj);
增删
// 比如,obj就是我,但是呢,是不是单身属于我的隐私,我不想别知道
let obj = { name: "颜酱", age: 18, phone: 18362780848, moonCake: 1 };
// 给我加个秘书
let proxy = new Proxy(obj, {
// 想吃掉我的月饼,那不行
deleteProperty(target, key) {
// target就是obj,key就是要删的属性
if (key !== "moonCake") {
// 要删除记得这里再次使用delete语法
delete target[key];
} else {
console.log("不能删除月饼");
}
// 如果这个方法返回false或者报错就会删除失败
return true;
},
// 想给我加食物,跟我说下. 这里注意增和改的操作都是set
set(target, key, value) {
const isAdd = !target.hasOwnProperty(key)
isAdd && console.log("加食物喽");
target[key] = value;
}
});
// 同理是 proxy而不是obj哈
delete proxy["moonCake"];
delete proxy["phone"];
proxy.waterMelon = 1;
// { name: '颜酱', age: 18, moonCake: 1, waterMelon: 1 }
console.log(proxy, obj);
proxy不能劫持到第二级的对象
就是对象套对象,只能劫持到第一层。
let obj = { name: "颜酱", age: 18, boyFriend: { name: "包子" } };
let proxy = new Proxy(obj, {
get(target, key) {
console.log(key);
return target[key];
},
set(target, key, value) {
console.log(key);
target[key] = value;
}
});
console.log(proxy.boyFriend.name);
proxy.boyFriend.name = "萌萌的包子";
console.log(proxy, obj);
深层监测,需要递归
所以如果想深层次监测对象,又要用到递归了。递归的逻辑在以往的文章中基本也用烂了,这里不多说。
function observeObj(obj) {
// 这边把handle拿出来,看着更清晰
const handle = {
get(target, key) {
console.log("get");
// 如果是对象的话就递归
if (typeof target[key] === "object" && target[key] !== null) {
return observeObj(target[key]);
}
return target[key];
},
set(target, key, value) {
console.log("set");
target[key] = value;
}
};
const proxy = new Proxy(obj, handle);
return proxy;
}
let obj = { name: "颜酱", age: 18, boyFriend: { name: "包子" } };
let x = observeObj(obj);
console.log(x.boyFriend.name);
x.boyFriend.name = "肉包子";
console.log(x, obj);
// 数组也行的哟~
let arr = [1, 2, 3, 4];
let x1 = observeObj(arr);
console.log(x1[2]);
x1[2] = 8;
console.log(x1, arr);