Vue响应式原理解析

2020-03-30  本文已影响0人  前端的爬行之旅

vue从改变一个数据到发生改变的过程

vue2

let ob = {
  a:1
}
Object.defineProperty(ob, 'a', {
  writable:false, // 属性值是否可写
  enumerable: false, // 属性值是否可循环
  configurable: false //属性值是否可以delete
})

Object.getOwnPropertyDescriptor(ob, 'a'); // 读取对象的属性值
let _value = ob.a;
// 如果想要使用get&set方法实现读取和存储,必须将属性值重新赋值给新的变量,来实现储存和中转,这也是defineProperty不优雅的一点。
// get & set 必须配合return方法使用。
Object.defineProperty(ob, 'a', {
  get () {
    return _value;
  },
  set (newValue) {
    _value = newValue
    return _value;
  }
})
// 实现vue简易版的双向原理
function Vue () {
  this.$data = {a:1};
  this.el = document.getElementById('app');
  this.vritualDom = '';
  this.observer(this.$data); //注册监听
  this.render();
}
// 注册get和set
Vue.prototype.observer = function (obj) {
  var value;
  var self = this;
  for (var key in obj) {
    value = obj[key];
    if (typeof value === 'object') {
      this.observer(value);
    } else {
      Object.defineProperty(obj, key, {
        get(){
          // 进行依赖收集
          // 为什么要收集依赖?
          // 数据可能只在局部位置使用,找到对应依赖,只更新依赖于变量的组件。
          return value;
        },
        set(newvalue){
          value = newvalue;
          self.render()
          return value;
        }
      })
    }
  }
};

Vue.prototype.render = function (obj) {
  this.vritualDom = 'i am' + this.$data.a;
  this.el.innerHTML = this.vritualDom;
}

defineProperty中的get和set是对象的属性,对数组如何实现处理?

// 数组的双向绑定就是做了一个设计者模式;
// 取出数组的原型链并拷贝;
var arraypro = Array.prototype;
var arrob =Object.create(arraypro);
var arrFun = ['push', 'pop', 'shift'];

arr.forEach((method .index) => {
  arrob[method] = function () {
    var ret = arraypro[method].apply(this, arguments);
    dep.notify() // 触发试图更新
  }
})

vue3

let obj = {
  a:1,
}
var obj = new Proxy(ob, {
  get (target, key, receiver) {
    return target[key];
  },
  set (target, key, value, receiver) {
    return Reflect.set(target, key, value)
    // return target[key] = value;
  }
})
// vue简易版的实现双向原理
function Vue () {
  var self = this;
  this.$data = new Proxy(this.$data, {
    get (target, key, receiver) {
      return target[key];
    },
    set (target, key, value, receiver) {
      target[key] = value;
      self.render();
      return target[key];
    }
  })
}

proxy的其他作用?

var validtor = {
  // 策略模式
  name: function (value) {
    var reg = /^[\u4E00-\u9FA5]+$/;
    if (typeof value == 'string' && reg.test(value)) {
      return true;
    }
    return false;
  },
  age: function (value) {
    if (typeof value == 'number' && value >= 18) {
      return true;
    }
    return false;
  },
}
function preson (age, name) {
  this.age = age;
  this.name = name;
  return new Proxy(this, {
    get (target, key) {
      return targe[key]
    },
    set (target, key, value) {
      if (validtor[key](value)) {
        return Reflect.set(target, key, value);
      } else {
        throw new Error(key + 'is not right')
      }
    }
  })
};

defineProperty 和 Proxy的区别

  1. defineProperty只能监听对象的某个属性,不能监听全对象;
  2. 可以省去defineProperty 中的for in 循环,节省性能
  3. 可以监听数组,不需要再去单独的对数组进行特异性处理;
  4. 不需要借助外部变量实现存储和读取(完善了vue2中defineProperty的不优雅的地方)
  5. 不会污染原对象(proxy对原对象进行代理,生成新的代理对象)
上一篇下一篇

猜你喜欢

热点阅读