手写代码,实现Vue2响应式


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 新增或者删除属性不能监听到;
  • 数组方法不能原生实现监听,需要额外处理;
posted @ 2022-03-29 22:57  Better-HTQ  阅读(126)  评论(0编辑  收藏  举报