实现一个observer方法——要监听的对象属性可配置

440 阅读2分钟

我正在参加「创意开发 投稿大赛」详情请看:掘金创意开发大赛来了!

实现一个observer方法

监听对象特定的属性,当被监听的属性发生变化的时候才触发回调函数打印输出,如果修改的是没有被监听的属性则不处理。

observer() 方法接收三个参数:

1. obj: 要监听的对象 Object 比如: {a: 1}

2. [path]: 要监听对象特定的属性路径 [String], 比如: ["obj.a"]

3. cb: 监听到指定属性变化时的回调函数,返回新值和旧值

思路分析

  1. 核心部分当然是 Object.defineProperty 劫持对象,在set方法里判断如果值发生改变,则调用 回调函数cb()

  2. 遍历 path 数组,只对指定的属性进行劫持,没有指定的属性不做处理

  3. 对 path 里的路径进行处理,从对象里获取到对应的属性值。

    • 👉这里要注意,深层级的路径要递归处理,递归传参要搞清楚 ❗

SHOW MY CODE

function observer(obj, path, cb) {
  path.forEach((key) => {
    let value = "";
    if (key) {
      const _key = key.split(".");
      if (_key.length > 1) {
        let tmp = obj;
        // 循环,为了取到属性值,不断地赋值给 tmp
        _key.forEach((k) => {
          // 递归,对每一个层级都进行劫持,要不然无法监听到深层级的属性值变化
          observer(tmp, [k], cb);
          tmp = tmp[k];
        });
        value = tmp;
      } else {
        value = obj[key];
      }

      Object.defineProperty(obj, key, {
        get() {
          return value;
        },
        set(newV) {
          if (newV !== value) {
            cb && cb(newV, value);
            value = newV;
          }
        },
      });
    }
  });
}

var o = {
  a: 1,
  b: 2,
  c: {
    x: 1,
    y: 2,
  },
};

observer(o, ['a',"c.x"], (v, prev) => {
  console.log("newV=", v, " oldV=", prev);
});

o.a = 2; // 2, 1
o.b = 3; // 不打印
o.c.x = 3; // 3, 1
o.c.y = 3; // 没有没监听,不打印

打印:劫持后的 obj

image.png 可以发现属性值以及被Getter/Setter转化了

小结

  1. Object.defineProperty 是高频使用的语法,Vue2 里面借助这个实现了很多功能,比如:data数据穿透,computed、methods等方法的代理,响应式原理…… 需要重点掌握的知识。

  2. 递归: 抽象思维,复杂问题简单化,代码更简洁。递归三要素👇

    • 明确你这个函数想要干什么

    • 寻找递归结束条件

    • 找出函数的等价关系式


🎈🎈🎈

🎉 喜欢的小伙伴可以点赞收藏关注

✨ 欢迎大家转发评论交流, 蟹蟹😊