Vue响应式原理

  /*
1.Vue是如何实现实时监听数据变化的?
通过原生JS的 defineProperty 方法

2.defineProperty方法的特点
可以直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象

3.defineProperty用法
obj: 需要操作的对象
prop:  需要操作的属性
descriptor: 属性描述符

Object.defineProperty(obj, prop, descriptor)

  */


  let obj = {};
  // 需求: 给obj对象动态新增一个name属性,并且name属性的取值必须是abc
  Object.defineProperty(obj, 'name', {
    value: 'abc',
    writable: true,  // true 新增的属性值可修改。默认不可修改
    configurable: true, // name属性是否可删除。默认不可删除
    enumerable: true, // 新增的name属性是否可迭代遍历。默认不可
  })

  console.log(obj)  // {name: "abc"}

// 默认不可删除新增的属性
delete obj.name
/*
3.1 defineProperty除了可以动态修改/新增对象的属性以外
还可以在修改/新增的时候给该属性添加get/set方法

3.2 get/set方法特点
只要通过defineProperty给某个属性添加了 get/set方法
那么以后只要获取这个属性的值就会自动调用get,设置了这个属性的值就会自动条用set

3.3注意点
如果设置了get/set方法,那么就不能通过value直接赋值,也不能设置writable: true
*/

let oldValue = "测试数据";
Object.defineProperty(obj, 'test', {
  configurable: true,
  enumerable: true,
  get() {
    return oldValue
  },
  set(newValue) {
    if(oldValue !== newValue) {
      oldValue = newValue;
    }
  }
})


// 需求:快速监听对象中所有属性的变化
let obj = {
  name: 'ceshi',
  age: 18
}

// 只要将需要监听的那个对象传递给Observer这个类
// 这个类就可以快速的给传入的对象的所有属性都添加get/set方法

class Observer {
  constructor(data) {
    this.observer(data);  // constructor 方法是类的默认方法,创建类的实例化对象时被调用。
  }

  observer(obj) {
    if(obj && typeof obj === 'object') {
      // 遍历取出传入对象的所有属性, 给遍历到的属性都增加get/set方法
      for(let key in obj) {
        this.defineRecative(obj, key, obj[key])
      }
    }
  }

  // obj: 需要操作的对象
  // attr: 需要新增get/set方法的属性
  // value: 需要新增get/set方法属性的取值
  defineRecative(obj, attr, value) {
    // 如果属性的取值又是一个对象, 那么也需要给这个对象的所有属性添加get/set方法
    this.observer(value);

    Object.defineProperty(obj, attr, {
      get(){
        return value;
      },
      set:(newValue)=>{
        if(value !== newValue){
          // 如果给属性赋值的新值又是一个对象, 那么也需要给这个对象的所有属性添加get/set方法
          this.observer(newValue);
          value = newValue;
          console.log('监听到数据的变化, 需要去更新UI');
        }
      }
    })
  }
}

new Observer(obj);
// obj.name = '123';
// obj.age = 23;
// obj.name.a = 'dtdgf';
obj.name = {a: 'abc'};
obj.name.a = '测试文本';
原文地址:https://www.cnblogs.com/yhquan/p/14551262.html