什么是vue2.x中Object的变化侦测?

痛定思痛,总要静一静,用抹布抹一抹陈旧模糊的记忆。

虽然截止至2023年12月31日,vue2.x版本已停止维护,但是vue2中的很多东西还是值得去思考的。

最经典的面试题莫过于:简述下Vue2的响应式原理~🤦‍♂️

what ?

什么是变化侦测?

说白话,就是界面视图发生改变时,需要有个人告诉我视图变了。

例:元宵节夜晚,当你一路向北行进时,背后方向忽然放起了烟花秀。迎面而来的一位美女,告诉了你。你转身回望赞叹了一句:"好漂亮~"

变化的事件:烟花秀

侦测者:美女

How?

如何追踪变化?

那么绕不开的一个方法必然就是 Object.defineproperty() ,建议通读其对象属性以便加深理解与感悟。

通过对其封装,得到如下函数,其作用是定义一个响应式数据。即在其中进行变化追踪,封装的目的在于仅仅传递入参即可。

js 复制代码
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;
    }
  })
}

关注点:

  • 每当从data的key中读取数据是,get函数被触发
  • 每当往data的key中设置数据时,set函数被触发

封装的目的:收集依赖

🤕 依赖是啥?---> 变化的信息(比如:之前提到的烟花秀)

一句话总结:先收集依赖,在getter中收集依赖,在setter中触发依赖

ps【通读 **Object.defineproperty()**后很好理解】:

getter---> get()函数对应的属性

setter---> set()函数对应的属性

存放依赖

⛏ 为啥存?---> 计算机处理数据,在输入后,需要存储才能进行后续操作。

这里定义了一个Dep类来收集、删除依赖或向依赖发送通知。

有时候,为了让自己开心,Dep可以是任何我喜欢的名字(比如:BBQ🤪)。

js 复制代码
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(windwo.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) {
            return arr.splice(index, 1)
        }
    }
}

既然有地方存依赖了,那么响应式函数就可以改造了

js 复制代码
function defineReactive (data, key, val) {
    let dep = new Dep() // 修改
    Object.defineProperty(data, key, {
        enumerable: true,
        configurable: true,
        get: function () {
            dep.depend() // 修改
            return val
        },
        set: function () {
            if(val === newVal) {
               return 
            }
            val = newVal
            dep.notify() // 修改
        }
    })
}

什么是watcher?

Watcher是一个中介的角色,数据变化时通知它,他负责通知其他地方。(比如:之前例子中的美女😁)

美女告诉了我背后有烟花秀,所以我才知道,并发出了赞美。

想要侦测所有

美女告诉我有烟花秀,仅仅是一件事。如果想知道更多的事应该怎么办?

答:住院

你一旦有什么事,护士会立马通知你~🤣

此时,则需要一个新的类 Observer,来实现将一个正常的Object转换成被侦测的Object。

解决方案是递归实现,此处不再展开。

关于Object的问题

如上所述,递归将一个正常的Object转换成被侦测的Object。然而,仅仅涵盖了Object本身已有的属性。

故无法追踪新增属性和删除属性

总结

🤕🤕🤕 欢迎讨论交流~

相关推荐
wshzd6 小时前
LLM之Agent(104)|DeepSeek-Harness(十三)ReactLoopAgent 总览:kick → turn → step
开发语言·前端·javascript
web打印社区6 小时前
远程打印:WebSocket 与 HTTP 轮询怎么选
前端·vue.js·websocket·网络协议·http·electron·pdf
天天喝旺仔7 小时前
浏览器渲染原理:从解析 HTML/CSS、构建渲染树到重排重绘与首屏优化
前端·javascript·css·性能优化·html
Days20508 小时前
时间胶囊项目正式发布
javascript·gpt·php
朱 欢 庆8 小时前
el-table-v2 虚拟表格组件
前端·javascript·vue.js
OpsEye8 小时前
企业大模型用量成本该如何监控和管控?
javascript·ai编程
杨利杰YJlio8 小时前
ITSK 万能驱动 26V5:新驱动批量更新
前端·javascript·后端
y = xⁿ9 小时前
关于Agent智能体开发
开发语言·前端·javascript
事圆则缓9 小时前
Flutter 状态管理框架对比(一):先看地图,再选工具
前端·javascript·flutter
IMPYLH9 小时前
HTML 的 <tfoot> 元素
前端·javascript·html