美文网首页
Vue Computed 原理

Vue Computed 原理

作者: 郝小淞 | 来源:发表于2018-08-24 11:26 被阅读0次

    Computed 计算属性是 Vue 中常用的一个功能,在使用中发现他像是介于datamethod之间的一个属性。他可以像是data一样在模板中<span>{{message}}</span>一样去使用,也可以通过this.message来调用;同时他也像method一样可以去处理数据逻辑。
    本片文章就简要分析一下computed的原理,在此之间需要了解一下Vue数据响应的原理Object.defineProperty中的get/set重写。

    原理解析

    特殊处理computed

    在Vue的实例化时,出入的对象中如果包含computed属性,构造内部会对这个对象进行特殊处理,处理成下一样的代码。

    // 1.0实例化
    var vm = new Vue({
        data () {
            return { }
        }
        computed: {
            // key:value,
            total: function _total() {
                return this.a * this.b
            }
        },
    })
    // computed转化
    var _computed = {
            // computed的key值与原先同名,新的value是一个队原先value封装的函数
        total: function(){
            // 在实例上挂载响应的属性,这样就可以像data一样使用 this.total === vm.total
            this.total = (function _total() {
                return this.price * this.num
            })()
        }
    }
    
    

    computed初始化

    初始化之后在vm上已经可以像data一样使用了

    
    let target = null // target 是重点
    // 遍历_computed
    Object.keys(_computed).forEach(key = {
        // 将key对应的function存入target中
        target = computed[key] // [function]
        // 执行target函数,函数内部更新了 vm[key] 的值
        target() 
        // 清空target
        target = null
    })
    
    

    监听和缓存

    computed的基本特性是:
    1、当data数据变更时,computed会更新
    2、当computed中没有引入的数据更新时,computed不会去重新计算,大幅度节省计算量

    实际是Vue内部创建了一个Dep

    get

    computed初始化 中的代码可以看到,_computedforEach的时候,target = _computed[key],也就是说,target执行的时候,如果内部触发get,那当前触发get属性的dep. depend函数中target函数中一定包含这个属性
    例如触发在_computed.total中触发this.priceget时候,target === _computed.totaldep. depend() 会将target_computed.total 存入 pricesubscribers中。

    这样每个data中的属性都有一个自己的subscribers,其中是跟自己相关的computed函数

    set

    当触发set的时候,就回去遍历执行subscribers中的函数

    this.price = 100这样更新时,this.price中的subscribers = [_computed.total, ...]this.subscribers.forEach((sub)=>{sub()})就会更新相关的computed

    
    // 订阅/发布模式
    class Dep {
        constructor () {
            // 调度中心 有几个computed引用到就有几个sub
            this.subscribers = []
        }
        // 发布 get的时候调用  
        depend () { 
            if(target && !this.subscribers.includes(target)) { // target存在并且调度中心没有
                this.subscribers.push(target) // 将target发布到调度中心
            }
        }
        // 订阅
        notify () {
            // 便利调度中心 更新所有引用了这个数据的computed
            this.subscribers.forEach((sub)=>{
                sub()
            })
        }   
    }
    
    Object.keys(data).forEach(key => {
        let internalValue = null
        const dep = new Dep()  // 闭包的方式实现,每一个data中的属性都会有一个自己Dep实例
        Object.defineProperty(data, key, {
            get () {
                dep.depend() // 当触发get的时候
                return internalValue
            }
            set (newVal) {
                internalValue = newVal
                dep.notify()  // 当触发set的时候
            }
        })
    })
    

    相关文章

      网友评论

          本文标题:Vue Computed 原理

          本文链接:https://www.haomeiwen.com/subject/qlfbiftx.html