vue响应式原理

221 阅读2分钟
let proto = Object.create(arrayProtos); //创建新的对象
['push', 'shfit', 'splice'].forEach(method => {
  proto[method] = function (...args) { //这个数组应该也被监控
    // console.log(arguments)
    let inserted; //默认没有插入新的数据
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args
        break;
      case 'splice': //数组splice只有传递三个参数,才有追加效果
        inserted = args.slice(2);
      default:
        break;
    }
    console.log('视图更新2')
    ArrayObserver(inserted)
    arrayProtos[method].call(this, ...args)
  }
});
//监控数组
function ArrayObserver(obj) {
  for (let i = 0; i < obj.length; i++) {
    let item = obj[i];
    //如果是普通值就不监控
    observer(item); //如果是对象会被defineReactive
  }
}

function observer(obj) {
  if (typeof obj !== 'object' || obj == null) {
    return obj;
  }
  if (Array.isArray(obj)) {
    //上面处理的是数组格式 push shift splice(如果调用这三个方法,应该把这个值判断以下是否是对象)
    // obj._proto_ = proto;
    Object.setPrototypeOf(obj, proto); //实现一个对数组的方法的重写
    // console.log(obj)
    ArrayObserver(obj)
    // for (let i = 0; i < obj.length; i++) {
    //   let item = obj[i];
    //   observer(item); //如果是对象会被defineReactive
    // }
  } else {
    //下面是处理对象的
    for (let key in obj) {
      defineReactive(obj, key, obj[key]);
    }
  }

}

function defineReactive(obj, key, value) {
  //默认只循环第一层
  observer(value); //递归创建响应式数据,但是会导致性能不好
  Object.defineProperty(obj, key, {
    get() {
      return value;
    },
    set(newValue) { //给某个key设置值的时候,可能也是一个对象
      if (value !== newValue) {
        observer(newValue)
        value = newValue
        console.log('试图更新')
      }
    }
  })
}
let data = {
  d: [1, 2, 3, {
    name: 'ccp'
  }]
};
observer(data);
data.d[3].name = 'cypjiayou'
data.d.push({
  name: 'ff'
})
// console.log(data.d[4])
// console.log(data.name)
//data.name = '123'; //vue缺点:1.增加不存在的的属性,不能更新视图。走set(vm.$set可以)
//data.name.n = '123' //2.vue默认会递归所有增加getter和setter
// data.name = {
//   n: 'js'
// }
// data.name = '123';
//vue特点:使用对象的时候,必须先申明属性,这个属性才是响应式的\
//3.数组里套对象 对象是支持响应式变化的,如果是常量则没有效果
//4.修改数组索引长度是不会导致视图更新的
//5.如果新增的数据,vue中也会帮你监控(对象类型)```