软件教程 2025年08月6日
0 收藏 0 点赞 379 浏览 3080 个字
摘要 :

文章目录 一、变化侦测的概念与类型 (一)什么是变化侦测 (二)变化侦测的类型 二、追踪Object变化的方法 三、依赖收集与相关概念 (一)依赖收集的位置与方式 (……




  • 一、变化侦测的概念与类型
    • (一)什么是变化侦测
    • (二)变化侦测的类型
  • 二、追踪Object变化的方法
  • 三、依赖收集与相关概念
    • (一)依赖收集的位置与方式
    • (二)Watcher的作用
  • 四、递归侦测对象的所有属性
  • 五、Object.defineProperty的局限性与Vue.js的解决方案

Vue.js Object的变化侦测机制 不仅是Vue.js响应式系统的核心,还影响着数据更新与视图渲染之间的交互逻辑。接下来,咱们就一起深入探究一下Vue.js中Object的变化侦测原理及实现方式。

一、变化侦测的概念与类型

(一)什么是变化侦测

在Vue.js应用里,状态(数据)与DOM之间存在紧密联系。Vue.js会依据状态自动生成DOM,并将其输出到页面进行显示,这个过程被称为渲染。然而,在应用运行时,内部状态是动态变化的,每当状态改变,往往需要重新渲染页面。此时,确定状态中具体发生了哪些变化就成了关键问题,而变化侦测正是用来解决这一难题的。

(二)变化侦测的类型

变化侦测主要分为“推”(push)和“拉”(pull)两种类型。像Angular和React中的变化侦测采用的是“拉”的方式,而Vue.js则使用“推”的机制。在Vue.js中,当状态发生变化时,它能够快速感知,并且在一定程度上明确哪些状态发生了改变。这就好比在一个团队里,有专人时刻关注成员的动态,一旦有人有变动,能马上知晓。

二、追踪Object变化的方法

在JavaScript中,有两种常用的方法来侦测一个对象的变化,分别是Object.defineProperty和ES6的Proxy。这里我们主要探讨Vue.js中基于Object.defineProperty的实现方式。

function defineReactive(data, key, val) {
    Object.defineProperty(data, key, {
        enumerable: true,
        configurable: true,
        get: function() {
            return val
        },
        set: function(newVal) {
            if (val === newVal) {
                return
            }
            val = newVal
        }
    })
}

这段代码通过Object.defineProperty为对象的属性定义了gettersettergetter用于获取属性值,setter则在属性值发生变化时被触发。不过,这段代码目前还只是基础示例,后续会进一步完善。

三、依赖收集与相关概念

(一)依赖收集的位置与方式

在Vue.js中,依赖收集是变化侦测的重要环节。依赖收集主要在getter中进行,而在setter中则会触发依赖。收集到的依赖会被存放在Dep类中。

export default class Dep {
    constructor() {
        this.subs = []
    }
    addSub(sub) {
        this.subs.push(sub)
    }
    removeSub(sub) {
        remove(this.subs, sub)
    }
    depend() {
        if (window.target) {
            this.addSub(window.target)
        }
    }
    notify() {
        const subs = this.subs.slice()
        for (let i = 0, l = subs.length; i < l; i++) {
            subs[i].update()
        }
    }
}
function remove(arr, item) {
    if (arr.length) {
        const index = arr.indexOf(item)
        if (index > -1) {
            arr.splice(index, 1)
        }
    }
}

Dep类就像是一个“仓库”,用来管理依赖。addSub方法用于添加依赖,removeSub方法用于移除依赖,depend方法在getter中被调用,用于收集依赖,notify方法则在setter中被触发,通知所有依赖进行更新。

(二)Watcher的作用

Watcher在Vue.js的变化侦测中扮演着中介角色。当数据发生变化时,会先通知Watcher,然后Watcher再通知其他相关地方。

export default class Watcher {
    constructor(vm, expOrFn, cb) {
        this.vm = vm
        this.getter = parsePath(expOrFn)
        this.cb = cb
        this.value = this.get()
    }
    get() {
        window.target = this
        let value = this.getter.call(this.vm, this.vm)
        window.target = undefined
        return value
    }
    update() {
        const oldValue = this.value
        this.value = this.get()
        this.cb.call(this.vm, this.value, oldValue)
    }
}

Watcher类的构造函数接收vm(Vue实例)、expOrFn(用于获取数据的表达式或函数)和cb(回调函数)。get方法用于收集依赖并获取数据,update方法在数据更新时被调用,执行回调函数cb,从而实现数据变化时的相关逻辑处理。

四、递归侦测对象的所有属性

前面的代码只能侦测对象中的某一个属性,为了实现对数据中所有属性的变化侦测,我们需要封装一个Observer类。

export class Observer {
    constructor(value) {
        this.value = value
        
        if (!Array.isArray(value)) {
            this.walk(value)
        }
    }
    
    walk(obj) {
        const keys = Object.keys(obj)
        for (let i = 0; i < keys.length; i++) {
            defineReactive(obj, keys[i], obj[keys[i]])
        }
    }
}


function defineReactive(data, key, val) {
    // 新增:递归子属性
    if (typeof val === \'object\') {
        new Observer(val)
    }
    let dep = new Dep()
    Object.defineProperty(data, key, {
        enumerable: true,
        configurable: true,
        get: function() {
            // 新增:收集依赖
            dep.depend()
            return val
        },
        set: function(newVal) {
            if (val === newVal) {
                return
            }
            val = newVal
            // 新增:触发依赖
            dep.notify()
        }
    })
}

Observer类的walk方法会遍历对象的所有属性,并通过defineReactive将每个属性都转换成getter/setter的形式,以便追踪它们的变化。同时,在defineReactive函数中,新增了对子属性的递归侦测、依赖收集和触发依赖的逻辑。

五、Object.defineProperty的局限性与Vue.js的解决方案

虽然Object.defineProperty能够将对象的属性转换成getter/setter形式来追踪变化,但它存在一定的局限性,无法追踪新增属性和删除属性的变化。因此,Vue.js专门提供了vm.$setvm.$delete方法来解决这一问题,让开发者在处理对象属性的添加和删除时更加灵活。

通过以上对Vue.js中Object变化侦测机制的深入讲解,相信大家对Vue.js的响应式原理有了更清晰的认识。在实际开发中,理解和掌握这些知识还是有点必要的。

微信扫一扫

支付宝扫一扫

版权: 转载请注明出处:https://www.zuozi.net/6894.html

管理员

相关推荐
2025-08-06

文章目录 一、Promise基础回顾 二、Promise 与 axios 结合使用场景及方法 (一)直接返回 axios …

269
2025-08-06

文章目录 一、模块初始化时的内部机制 二、常见导出写法的差异分析 (一)写法一:module.exports…

107
2025-08-06

文章目录 一、ResizeObserver详解 (一)ResizeObserver是什么 (二)ResizeObserver的基本用法 …

683
2025-08-06

文章目录 一、前期准备工作 (一)下载相关文件 (二)安装必要工具 二、处理扣子空间生成的文件…

338
2025-08-06

文章目录 一、官方文档 二、自动解包的数据类型 ref对象:无需.value即可访问 reactive对象:保持…

371
2025-08-06

文章目录 一、Hooks的工作原理 二、在if语句中使用Hook会出什么岔子? 三、React官方的Hook使用规…

843
发表评论
暂无评论

还没有评论呢,快来抢沙发~

助力内容变现

将您的收入提升到一个新的水平

点击联系客服

在线时间:08:00-23:00

客服QQ

122325244

客服电话

400-888-8888

客服邮箱

122325244@qq.com

扫描二维码

关注微信客服号