proxy监测属性变化

4,160 阅读3分钟

监测属性变化的有 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);