vue响应式原理

vue响应式是通过Object.defineProperty结合发布者订阅者模式实现的。

通过Object.defineProperty 实现数据劫持,将data中的所有属性都转变为getter和setter

订阅者 – Watcher

update():更新函数

发布者 – Dep:

  • subs 数组:存储data中某属性所有的订阅者,即存的是调用Watcher构造函数生成的实例对象。
  • addSub():添加订阅者
  • notify():当data中某属性变化时,set被触发,调用该属性所有订阅者的 update() 方法

基本实现:

    // 当前活跃的 Watcher
    let activeWatcher = null;


    //订阅者
    class Watcher {
        constructor(cb) {
            // 更新函数
            this.cb = cb;
            // 初始化时执行更新函数
            this.update();
        }
        // 数据更新时,调用该函数重新求值
        update() {
            // 调用更新函数时,将 activeWatcher 指向当前 watcher
            activeWatcher = this;
            this.cb();
            // 调用完重置
            activeWatcher = null;
        }
    }
    

    //发布者
    class Dep {
        constructor() {
            // 保存所有该依赖项的订阅者
            this.subs = [];
        }
        addSubs(activeWatcher) {
            this.subs.push(activeWatcher);
        }
        notify() {
            this.subs.forEach((watcher) => {
                watcher.update();
            });
        }
    }
    
    //把普通对象转化为响应式对象
    class Observer {
        constructor(value) {
            this.value = value;
            this.walk(value);
        }
        // 遍历 keys,转换为 getter/setter
        walk(obj) {
            const keys = Object.keys(obj);
            for (let i = 0; i < keys.length; i++) {
                const key = keys[i]
                defineReactive(obj, key, obj[key]);
            }
        }
    } 

    function defineReactive(target, key, value) {
        const dep = new Dep()  // data中的每一个属性都是一个发布者
        Object.defineProperty(target, key, {
            enumerable: true,
            configurable: true,
            get() {
                dep.addSubs(activeWatcher)  //收集该属性所有的订阅者,存放在dep的subs数组中
                return value
            },
            set(newValue) {
                // 如果前后值相等,没必要跟新
                if (value === newValue) {
                    return
                }
                value = newValue
                // 派发更新
                dep.notify()   //该方法会调用dep的subs数组中存放的所有订阅者的更新函数。
            }
        })
    }

测试一下

    let data = {
        name: "张三",
        age: 18
    };

    const box1 = document.getElementById('box1')
    const box2 = document.getElementById('box2')


    //订阅者1的更新函数
    const watcher1 = () => {
        box1.innerText = `名字为:${data.name},年龄为:${data.age}`
    }    
   //订阅者2的更新函数
    const watcher2 = () => {
        box2.innerText = `名字为:${data.name},年龄为:${data.age}`
    }
    //订阅者1
    new Watcher(watcher1)
    //订阅者2
    new Watcher(watcher2)


    //把data对象变成响应式
    new Observer(data)


    //1s后更新data中的数据
    setTimeout(()=>{
        data.name = "李四"
        data.age = 20
    },1000)

运行结果

1s后

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值