vue源码讲解----数据响应式原理

2023-10-27 16:07:58 浏览数 (1)

数据响应式原理是我们在开发过程中一定要了解的知识,彻底搞懂数据响应式原理,刻不容缓。

Object.defineProperty()方法

首先我们应该知道Vue采用数据劫持 发布者-订阅者模式实现双向数据绑定, 然后我们来看一下Object.defineProperty()方法,此方法会直接在对象上定义属性,或者修改一个对象的现有属性,并返回此对象

代码语言:javascript复制
let obj = {};  
Object.defineProperty(obj, 'a', {  
    value: 1 
});  
Object.defineProperty(obj, 'b', {  
    value: 2 
});  
console.log(obj);   //{a:1,b:2}
console.log(obj.a, obj.b); //1,2

Object.defineProperty()方法还可以设置一些额外的隐藏属性。

代码语言:javascript复制
Object.defineProperty(obj, 'a', {  
    value: 1 ,
    // 是否可写  
    writable: false
});  
Object.defineProperty(obj, 'b', {  
    value: 2 ,
   // 是否可以被枚举  
    enumerable: false
}); 

getter和setter

get 属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象 (由于继承关系,这里的 this 并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认为 undefined。 set 属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值) ,会传入赋值时的 this 对象默认为 undefined。 文字有些晦涩难懂,看代码会更好理解些

代码语言:javascript复制
Object.defineProperty(obj,'a'{
    //getter
    get(){
        console.log("你试图访问obj的a属性');
    }
    //setter
    set() {
        console.log("你试图改变obj的a属性');
    }
 })
console.log(obj.a);
obj.a = 10;

defineReactive函数

getter/setter需要变量转换

代码语言:javascript复制
var temp;:
Object.defineProperty(obj,'a',[
    get(){
        console.log("你试图访问obj的a属性');return temp;
    }
    set(newValue) {
        console.log("你试图改变obj的a属性’,newValue);
        temp = newValue;
    }
})

但是使用defineReactive函数就不用设置临时变量了,用闭包即可。

代码语言:javascript复制
function defineReactive(data,key,val) {
  Object.defineProperty(data,key,{
    enumerable: true,
    configurable:true,
    get() {
      console.log('访问obj的key属性')
    },
    set(newVal) {
      console.log('改变obj的key属性',)
      if(val === newVal) {
        return 
      }
      val = newVal
    }
  })
}

对象响应式处理

通过observe,将一个正常的object转换为每个层级 的属性都是响应式(可以被侦测的)的object

代码语言:javascript复制
function Observer(data) {
    this.data = data;
    this.walk(data);
}
Observer.prototype = {
    walk: function(data) {
    var self = this;
    Object.keys(data).forEach(function(key) {
    self.convert(key, data[key]);
    });
},
convert: function(key, val) {
    this.defineReactive(this.data, key, val);
},
defineReactive: function(data, key, val) {
    var dep = new Dep();
    var childObj = observe(val);
    Object.defineProperty(data, key, {
    enumerable: true,
    configurable: true,
    get: function() {
    if (Dep.target) {
        dep.depend();
    }
        return val;
    },
    set: function(newVal) {
        if (val === newVal) {
        return;
    }
    val = newVal;
    childObj = observe(newVal);
    dep.notify();
    }
   });
 }
};
function observe(value, vm) {
    if (!value || typeof value !== 'object') {
    return;
}
    return new Observer(value);
};

如上代码所示,Observer会对数据进行劫持并且在每个数据属性中创建一个对应的Dep实例。Dep是Vue.js中的一个订阅者列表,用于收集依赖于该对象的所有Watcher对象,在数据变化时执行相应的update回调函数。当一个数据对象被监听后,Observer就会将其属性进行劫持,通过Object.defineProperty将属性改成getter/setter的形式,并当属性被读取时自动收集相应的Watcher对象,在属性变化时自动触发相应的更新逻辑。

Observer是Vue.js变化侦测系统中最为核心和重要的部分。通过Observer监听数据的变化并更新视图,才能实现Vue.js的双向数据绑定和响应式的数据更新机制。

数组的响应式处理

数组的响应式通过重写数组的方法来实现响应式(push,pop,shift,unshift,splice,sort,reverse)

至此数据响应式原理讲解完毕,如有错误,敬请指正。

0 人点赞