vue-computed实现原理

1,计算属性的用法

vue中计算属性能够实现一个数据依赖其他数据的变化而变化,话不多说先上代码

 1 new Vue({
 2         data:{
 3             a:1
 4         },
 5         mounted(){
 6             const that = this
 7             setTimeout(function(){
 8                 that.a = 2
 9             },2000)
10         },
11         computed:{
12             b:function(){
13                 console.log("现在b的值是",this.a+1)
14                 return this.a + 1
15             }
16         }
17     })

在computed中定义一个 计算属性(函数),这个函数中涉及到data中的所有数据,都会被收集起来,将他们作为这个属性计算的依赖,当这些依赖发生变化时,就会执行这个计算属性对应的函数。比如上面的例子中,b的计算属性函数中有this.a,a是data中的数据,那a将会作为b计算属性的一个依赖被收集起来,第8行中that.a = 2,此时a的值发生变化,触发b的计算属性函数,这样就完成了一次计算。

2,计算属性的原理

有这么一个方法 Object.defineProperty(),先让我们看看这个方法是怎么用的。

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

 Object.defineProperty(obj, prop, descriptor) 

参数:

obj 要定义属性的对象。
prop 要定义或修改的属性的名称或 Symbol
descriptor 要定义或修改的属性描述符。
其中第三个参数descriptor是一个json,有兴趣的可以去 Object.defineProperty()研究一下。我们这里主要是看set(属性的setter函数),get(属性的getter函数)
话不多说,先上代码
var obj = {}
    Object.defineProperty(obj,"a",{
        set:function(val){
            console.log("set函数执行")
            this._a = val // 定义一个_a作为一个私有属性,来记录a属性的值
        },
        get:function(){
            console.log("get函数执行")
            return this._a
        }
    })
    obj.a = "123"
    // set函数执行
    console.log(obj.a)
    // get函数执行
    // 123

 上面的代码 可以看出 只要执行obj.a = xxx 就会执行 obj中a属性的set函数,只要执行obj.a 就会调用obj中a属性的get函数

3,属性计算的实现

vue中属性计算利用函数闭包和对象属性set,get函数 完美实现

 1    var Dep = null  
 2     function defineReactive(obj,key,val){
 3         var deps = [] // deps 收集依赖用
 4         Object.defineProperty(obj,key,{
 5             get:function(){
 6                 if(Dep){
 7                     deps.push(Dep)
 8                 }
 9                 return val
10             },
11             set:function(newVal){
12                 val = newVal;
13                 deps.forEach(func=>func()) // deps 在set函数中被引用 形成闭包
14             }
15         })
16     }
17 
18     function defineComputed(obj,key,func){
19         func = func.bind(obj)
20         var value
21         Dep = function(){
22             value = func() // value 在此函数中被引用 形成闭包
23         }
24         value = func() // 执行一次 属性计算函数,计算属性函数中的this.a(36行)的执行,会执行a的get函数(5行),将计算属性函数放到依赖项中(第7行)
25         Dep = null
26         Object.defineProperty(obj,key,{
27             get:function(){
28                 return value // value 在set函数中被引用 形成闭包
29             }
30         })
31     }
32 
33     var obj = {}
34     defineReactive(obj,"a",0)
35     defineComputed(obj,"b",function(){
36         var a = this.a
37         return a + 1
38     })

执行上面的代码,在控制台输入

 console.log(obj.b) obj.a += 1; console.log(obj.b); obj.a += 1; console.log(obj.b); obj.a += 1; console.log(obj.b);
 测试一下,完美打印出 1, 2, 3, 4
通过对存取器属性、闭包和观察者模式的综合运用,Vue 巧妙的实现了计算属性。现在再看官方文档描述,是不是更通透了呢。 可以看出,Vue 响应式系统的核心理念是“依赖”,DOM 节点之所以随数据而变化,是因为节点依赖于数据,计算属性之所以随数据而变化,是因为计算属性依赖于数据。做好响应式的关键就在于处理好依赖关系。 

猜你喜欢

转载自www.cnblogs.com/preciousness/p/13202006.html