VUE是如何实现响应式的

关键:Object.defineProperty()
将data的属性代理到vm上
修改data属性后,vue能立刻监听到
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue2 的响应式原理主要是基于 Object.defineProperty() 函数实现的。 Vue2 通过对数据对象的访问拦截,在访问数据对象的时候自动触发依赖收集和派发更新操作。具体实现步骤如下: 1. 遍历数据对象的所有属性,为每个属性创建一个独立的依赖收集器(Dep)对象。 2. 对访问数据对象的方法进行重写,使其在访问数据对象的属性时,将当前正在执行的 Watcher 对象添加到该属性对应的依赖收集器中。 3. 对修改数据对象的方法进行重写,使其在修改数据对象的属性时,触发该属性对应的依赖收集器对象的派发更新操作,通知所有依赖于该属性的 Watcher 对象更新视图。 具体实现代码如下: ```javascript function defineReactive(obj, key, val) { const dep = new Dep(); // 创建依赖收集器对象 Object.defineProperty(obj, key, { enumerable: true, configurable: true, get: function reactiveGetter() { if (Dep.target) { dep.depend(); // 将当前 Watcher 对象添加到依赖收集器中 } return val; }, set: function reactiveSetter(newVal) { if (newVal === val) { return; } val = newVal; dep.notify(); // 触发依赖收集器对象的派发更新操作,通知所有 Watcher 对象更新视图 } }); } function observe(obj) { if (!obj || typeof obj !== 'object') { return; } Object.keys(obj).forEach(key => { defineReactive(obj, key, obj[key]); }); } class Watcher { constructor(vm, expOrFn, cb) { this.vm = vm; this.getter = parsePath(expOrFn); this.cb = cb; this.value = this.get(); } get() { Dep.target = this; const value = this.getter.call(this.vm, this.vm); Dep.target = null; return value; } update() { const oldValue = this.value; this.value = this.get(); this.cb.call(this.vm, this.value, oldValue); } } class Dep { constructor() { this.subs = []; } addSub(sub) { this.subs.push(sub); } removeSub(sub) { remove(this.subs, sub); } depend() { if (Dep.target) { Dep.target.addDep(this); } } notify() { const subs = this.subs.slice(); for (let i = 0, l = subs.length; i < l; i++) { subs[i].update(); } } } Dep.target = null; const targetStack = []; function pushTarget(target) { targetStack.push(target); Dep.target = target; } function popTarget() { targetStack.pop(); Dep.target = targetStack[targetStack.length - 1]; } function parsePath(path) { const segments = path.split('.'); return function(obj) { for (let i = 0; i < segments.length; i++) { if (!obj) { return; } obj = obj[segments[i]]; } return obj; }; } function remove(arr, item) { if (arr.length) { const index = arr.indexOf(item); if (index > -1) { return arr.splice(index, 1); } } } class Vue { constructor(options) { this._data = options.data; observe(this._data); this._watchers = []; this._initWatchers(options); } _initWatchers(options) { const watchers = options.watch || {}; for (let key in watchers) { const handler = watchers[key]; this.$watch(key, handler); } } $watch(expOrFn, cb) { const watcher = new Watcher(this, expOrFn, cb); this._watchers.push(watcher); return function unwatch() { watcher.teardown(); }; } } ``` 上述代码中,defineReactive 函数用于将一个属性变成响应式的,observe 函数用于遍历数据对象的所有属性并调用 defineReactive 函数,Watcher 类用于封装一个 Watcher 对象,Dep 类用于封装一个依赖收集器对象。Vue 类则用于封装一个 Vue 实例,实现了 $watch 方法用于监听数据的变化,并创建 Watcher 对象。在 Watcher 对象的构造函数中,会调用 parsePath 函数将表达式字符串转换成一个函数,然后调用该函数获取数据对象的值,并触发依赖收集。在数据对象的属性被修改时,会触发该属性对应的依赖收集器对象的派发更新操作,通知所有 Watcher 对象更新视图。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值