区分Vue2 与 Vue3 响应式原理

308 阅读1分钟

vue2.x的响应式

实现原理:

  • 对象类型:通过Object.defineProperty()对属性的读取、修改进行拦截(数据劫持)。

  • 数组类型:通过重写更新数组的一系列方法来实现拦截。(对数组的变更方法进行了包裹)。

Object.defineProperty(data, 'count', {
    get () {}, 
    set () {}
})

存在问题:

  • 新增属性、删除属性, 界面不会更新。
  • 直接通过下标修改数组, 界面不会自动更新。

Case:

let person = {
  name: '张三',
  age: 18,
}

// 模拟Vue2中响应式实现
let p = {};
Object.defineProperty(p, 'name', {
  configurable: true,
  // 读取name时调用
  get(){
    return person.name;
  }
  // 修改name时调用
  set(value){
    console.log('修改了name属性,我发现了,我要去更新页面!')
    person.name = value;
  }
})

Object.defineProperty(p, 'age', {
  configurable: true,
  // 读取age时调用
  get(){
    return person.age;
  }
  // 修改age时调用
  set(value){
    console.log('修改了age属性,我发现了,我要去更新页面!')
    person.age = value;
  }
})

Vue3.0的响应式

实现原理:

new Proxy(data, {
// 拦截读取属性值
  get(target, prop) {
        return Reflect.get(target, prop)
  },
  // 拦截设置属性值或添加新属性
  set(target, prop, value) {
        return Reflect.set(target, prop, value)
  },
  // 拦截删除属性
  deleteProperty(target, prop) {
        return Reflect.deleteProperty(target, prop)
  }
})

Case:

let person = {
    name: '张三',
    age: 18
}

// 模拟Vue3实现响应式
const p = new Proxy(person, {
    // 读取p的某个属性时调用
    get(target, propName){
      console.log(`有人读取了p的${propName}属性`);
      return Reflect.get(target, propName);
    },

    // 修改p的某个属性、或给p新增某个属性时调用
    set(target, propName, value){
      console.log(`有人修改了p的${propName}属性,我要去更新界面了`);
      Reflect.set(target, propName, value);
    },

    // 删除p的某个属性时调用
    deleteProperty(target, propName){
      console.log(`有人删除了p的${propName}属性,我要去更新界面了`);
      return Reflect.deleteProperty(target, propName);
    },
})