• 手写代码,实现Vue2响应式 Better



    Object.defineProperty 应用

    const data = {};
    let name = 'hello';
    Object.defineProperty(data, 'name', {
      get: function() {
        console.log('>>> get');
        return name;
      },
      set: function(newVal) {
        name = newVal;
        // 更新视图
        console.log('>>> 更新视图');
      }
    })
    
    data.name; // >>> get
    data.name = 'world'; // >>> 更新视图
    

    基本实现

    const data = {
      name: 'zhangsan',
      age: 28
    }
    
    observer(data)
    
    function observer(target) {
      if (typeof target !== 'object' || target === null) {
        return target;
      }
      for (let key in target) {
        defineReactive(target, key, target[key]);
      }
    }
    
    function defineReactive(target, key, value) {
      Object.defineProperty(target, key, {
        get() {
          return value;
        },
        set(newVal) {
          if(newVal !== value) {
            value = newVal;
            console.log('>>> 更新视图')
          }
        }
      })
    }
    
    data.name = 'lisi' // >>> 更新视图
    

    实现深度监听

    const data = {
      name: 'zhangsan',
      age: 28,
      friend: {
        name: 'wangwu'
      }
    }
    
    observer(data)
    
    function observer(target) {
      if (typeof target !== 'object' || target === null) {
        return target;
      }
      for (let key in target) {
        defineReactive(target, key, target[key]);
      }
    }
    
    function defineReactive(target, key, value) {
      observer(value) // 实现深度监听
      Object.defineProperty(target, key, {
        get() {
          return value;
        },
        set(newVal) {
          if(newVal !== value) {
            value = newVal;
            console.log('>>> 更新视图')
          }
        }
      })
    }
    
    data.friend.name = 'wangwu2' // >>> 更新视图
    

    监听增加的数据层级

    const data = {
      name: 'zhangsan',
      age: 28,
    }
    
    observer(data)
    
    function observer(target) {
      if (typeof target !== 'object' || target === null) {
        return target;
      }
      for (let key in target) {
        defineReactive(target, key, target[key]);
      }
    }
    
    function defineReactive(target, key, value) {
      observer(value)
      Object.defineProperty(target, key, {
        get() {
          return value;
        },
        set(newVal) {
          observer(newVal) // 监听新增的对象属性
          if(newVal !== value) {
            value = newVal;
            console.log('>>> 更新视图')
          }
        }
      })
    }
    
    data.age = { number: 25} // >>> 更新视图
    data.age.number = 27 // >>> 更新视图
    

    数组方法响应式实现

    const oldArrayProto = Array.prototype;
    const newArrayProto = Object.create(oldArrayProto);
    ['push', 'pop', 'shift', 'unshift', 'splice'].forEach((method) => {
      oldArrayProto[method].call(this, ...arguments);
      console.log('更新视图');
    })
    
    function observer(target) {
      if (typeof target !== 'object' || target === null) {
        return target;
      }
      if (Array.isArray(target)) {
        target.__proto__ = newArrayProto; // 修改数组实例的原型
      }
      for (let key in target) {
        defineReactive(target, key, target[key]);
      }
    }
    
    function defineReactive(target, key, value) {
      ...
    }
    

    vue2 实现响应式的不足

    • 数据层级很深的时候,一开始就需要设置全部数据的监听,很费性能;
    • data 新增或者删除属性不能监听到;
    • 数组方法不能原生实现监听,需要额外处理;
  • 相关阅读:
    ios端浏览器拍照上传到服务器,图片被旋转90度 php 解决方案
    wgs84 转百度经纬度坐标
    vue 编译大量空格警告问题总结 warning: Replace `↹↹` with `··`
    微信sdk php签名方法整理
    Vue 使用百度地图组件
    php unicode转字符串
    第十篇、微信小程序-view组件
    第九篇、微信小程序-button组件
    第八篇、微信小程序-progress组件
    第七篇、微信小程序-video组件
  • 原文地址:https://www.cnblogs.com/huangtq/p/16074324.html
Copyright © 2020-2023  润新知