Vue源码之Object数据劫持

目录

vue中如何侦测Object变化?

js中两种侦测对象变化方法:

  • 使用Object.defineProperty
  • ES6的proxy(ES6浏览器支持不理想)
Object.defineProperty

该方法定义一个响应式数据,当数据的属性发生变化的时候,通知依赖更新,即向使用到它的地方发送通知

Object可以通过Object.defineProperty将属性转换成getter/setter的形式来追踪变化。读取数据时会触发getter,修改数据时会触发setter

Object.defineProperty(obj, key, {
        get() {
            return val;
        },
        set(newVal) {
            if (newVal !== val) {
                val = newVal
            }
        }
})

这样,修改数据时,我们可以主动通知依赖进行更新,那么问题来了:

  1. 如何收集依赖?什么时机收集依赖?

    思路:

    1. 任何地方,只要涉及到数据读取,就会触发get函数
    2. 先收集依赖,然后等属性发生变化的时候,再把之前收集好的依赖循环触发一遍就好了

    总结:在getter中收集依赖,在setter中触发依赖

  2. 依赖收集在哪里?

    定义一个Dep类,用来存储当前key的依赖。DEP类主要负责对依赖的收集、删除、发送通知。

  3. 依赖是谁?

    依赖就是用到数据的地方,用到这个数据的地方可能是视图中对应的坑({ {name}}),也可能是开发者写的一个watch,于是抽象一个类Watcher

至此,问题告一段落

  • 定义一个响应式数据
//数据劫持,添加依赖追踪
    defineReactive(obj, key, val) {
        const dep = new Dep();
        Object.defineProperty(obj, key, {
            get() {
                //只有Watcher触发的getter才会收集依赖
                Dep.target && dep.depend(); 
                return val;
            },
            set(newVal) {
                if (newVal !== val) {
                    val = newVal;
                    // 数据发生变更通知所有的观察者
                    dep.notify()
                }
            }
        })
        //递归树
        this.observer(val);
    }
  • 定义一个Dep类,收集依赖
// Dep发布者相当于vue data 对象中的某一个属性如:name
class Dep {
    constructor(vm, key) {
        this.subs = [];
    }
    
    depend() {
        if (Dep.target) {
            this.addSub(Dep.target)
        }
    }
    addSub(sub) {
        this.subs.push(sub);
    }
    removeSub(sub) {
        remove(this.subs, sub);
    }

    notify() {
        //只负责通知更新,具体是否更新以及更新操作由watcher做
        this.subs.forEach(sub => sub.update())
    }
}

  • 定义依赖 – Watcher类

当new Watcher()实例时,会自动将依赖收集到Dep中

// watcher 相当于视图中对应的坑({
  {name}}),一个坑对应有一个观察者,监听此处的数据变化
class Watcher {
    constructor(v
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值