最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Vue新老数据双向绑定比较

    正文概述 掘金(leonsux)   2021-01-27   474

    Object.defineProperty

    因此,可以通过设置属性的 set 方法来实现监听数据变化的效果。

    const obj = {
        a: 1,
        b: [1, 2],
    };
    for (let key in obj) {
      let _val = obj[key];
      Object.defineProperty(obj, key, {
        get() {
          console.log('get ', key);
          return _val;
        },
        set: (value) => {
          console.log(`set ${key}: `, value);
          _val = value;
        },
      });
    }
    obj.a = 2;
    console.log(obj.a);
    obj.b = [3, 4];
    console.log(obj.b);
    
    // set a 2
    // get a
    // 2
    // set b [3, 4]
    // get b
    // [3, 4]
    

    这样一看没什么问题, 但是当通过数组方法去改变值时,会发现并没有被 set 监听到。

    obj.b.push(5);
    console.log(obj.b);
    
    // [1, 2, 5] b的值正确没问题,push进去了,但是没有set b
    

    因为我们是调用了数组方法,而不是通过 obj.b = [] 重新赋值,所以解法也简单:重写数组方法,让我们的数组去继承这些方法

    const obj = {
        a: 1,
        b: [1, 2],
    };
    const aim = []; // 定义一个工具人数组,下面重写其方法,最后让其他数组的去继承其方法
    const arrayMethods = ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'];  
    // 重写工具人的方法
    arrayMethods.forEach(item => {
        Object.defineProperty(aim, item, {
            value() {
                console.log(`call ${item}`);
                [][item].apply(this, arguments);
            },
        })
    });
    obj.b.__proto__ = aim; // 让我们的数据继承工具人的方法
    obj.b.push(3);
    console.log(obj.b);
    
    // call push
    // [1, 2, 3]
    

    简单整合后如下

    const obj = {
        a: 1,
        b: [1, 2],
    };
    const aim = []; // 定义一个数组,下面重写其方法,最后让其他数组的去继承其方法
    const arrayMethods = [
      'push',
      'pop',
      'shift',
      'unshift',
      'splice',
      'sort',
      'reverse',
    ];
    
    arrayMethods.forEach(item => {
      Object.defineProperty(aim, item, {
        value() {
          console.log(`call ${item}`);
          [][item].apply(this, arguments);
        },
      })
    });
    
    for (let key in obj) {
      if (Array.isArray(obj[key])) {
        obj[key].__proto__ = aim;
      } else {
        let _val = obj[key];
        Object.defineProperty(obj, key, {
          get() {
            console.log('get ', key);
            return _val;
          },
          set: (value) => {
            console.log(`set ${key}: `, value);
            _val = value;
          },
        });
      }
    }
    
    obj.a = 2;
    console.log(obj.a);
    obj.b.push(3);
    console.log(obj.b);
    

    Proxy

    原理和上面类似,监听属性值变化

    const obj = {
        a: 1,
        b: [1, 2],
    };
    const objProxy = new Proxy(obj, {
      get(target, prop, receiver) {
        console.log('get', prop);
        return target[prop];
      },
      set(target, prop, value, receiver) {
        console.log('property set: ' + prop + ' = ' + value);
        target[prop] = value;
        return true;
      },
    });
    objProxy.a = 2;
    console.log(objProxy.a);
    
    // property set: a = 2
    // get a
    // 2
    
    objProxy.b.push(3);
    console.log(objProxy.b);
    
    // get b
    // get b
    // 3
    

    通过上面代码可以看到,属性 a 的监听没问题,但是属性 b 数组的变化还是没有监听到,因为通过这种方式我们监听的是 b 地址值(数组是由一个地址值地址值指向的堆空间里的数据组成的),我们通过 push 并没有改变地址值,而是改变堆栈中的值,所以没有监听到。解决方法也简单:如果是数组,再次创建一个 Proxy 对象去监听

    const obj = {
        a: 1,
        b: [1, 2],
    };
    const fnProxy = (obj) => {
      const objProxy = new Proxy(obj, {
        get(target, prop, receiver) {
          console.log('get', prop);
          if (Array.isArray(target[prop])) {
            return fnProxy(target[prop]);
          }
          return target[prop];
        },
        set(target, prop, value, receiver) {
          console.log('property set: ' + prop + ' = ' + value);
          target[prop] = value;
          return true;
        },
      });
      return objProxy;
    };
    fnProxy(obj);
    const objProxy = fnProxy(obj);
    objProxy.b.push(10);
    console.log(objProxy.b);
    
    // get b
    // get push
    // get length
    // property set: 2 = 10   这个 ‘2’ 是数组下标
    // property set: length = 3
    // get b
    // [1, 2, 10]
    

    上面的代码中将生成Proxy对象的操作封装了一个方法,如果目标值是数组,就将目标值作为入参再次调用该方法,通过递归的方式完成对数组变化的监听。


    起源地下载网 » Vue新老数据双向绑定比较

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元