巴彦淖尔市网站建设_网站建设公司_关键词排名_seo优化
2026/1/21 19:16:59 网站建设 项目流程
let arr=[1,2,3] arr[0]=10

没有效果

这种情况,是因为Object.definePropoty监视不了数组的索引

let arr2 = [{name:"张三"}] arr2[0].name = "李四"

有效果

这种情况是因为这里arr2[0]拿到的是{name:"张三"}这个对象,Object.defineProperty本身只能监视「已存在的属性」的「读取 / 修改」行为,这里对象的name属性已经存在,对name属性修改可以

let arr3 = [{name:"张三"}] arr3[0] = {name:"李四"}

没有效果[视图不更新]

这个操作的本质是修改数组的索引 0 对应的「值」(把原来的对象替换成新对象),而非修改原有对象的属性。

就像arr[0]=10一样,数组索引的修改无法被Object.defineProperty监听,因此不会触发视图更新。

总结:vue2的响应式实现就是通过Object.definePropoty,Object.definePropoty监视不了对象属性的新增和删除,也处理不了数组索引,所以为啥对象新增和删除属性不会触发视图更新,数组通过索引修改,也不会触发视图更新

2关于$set解决Vue2响应式丢失

// 给对象添加属性 this.$set(目标对象, 要新增/修改的属性名, 属性值) // 给数组修改元素 this.$set(目标数组, 数组索引, 新值)

$set里,它的作用就是给原本没有监听的新属性(如age)补上这两个开关,让 Vue 能 “看到” 这个属性的读写操作。

2. dep.notify ():触发 “更新通知”

dep是依赖收集器(Dep 实例),里面存着所有用到这个属性的视图 /watch 对应的 Watcher 实例;dep.notify()就是dep的 “通知方法”:

$set里,它的作用有两个:

  • 补全响应式劫持:Vue2 初始化时只给data里已有的属性加getter/setter(用来监听读写),新增的属性 / 数组索引修改不会自动加。$set会手动调用Object.defineProperty(对象场景)或重写的splice方法(数组场景),给新内容补上这个 “监听开关”。

  • 关联依赖更新:光有监听还不够,$set会把新内容的监听逻辑,挂靠到目标对象 / 数组的__ob__.dep(依赖收集器)上。这样修改新内容时,能触发dep.notify()通知视图更新,相当于把新内容 “拉进” 了 Vue 的响应式体系里。

  • 主动触发一次更新:最后$set会主动调用dep.notify(),确保新增的内容能立刻在视图上显示,不用等下一次更新周期。

  • 1. Object.defineProperty:给属性装 “监听开关”

    它是 Vue2 实现响应式的底层核心 API,作用就是手动给对象的属性绑定getter(读监听)和setter(写监听):

  • getter(读开关):当页面读取这个属性(比如<p>{{user.age}}</p>)时触发,核心是把 “当前用到这个属性的视图 /watch” 加入dep(依赖收集);
  • setter(写开关):当你修改这个属性(比如user.age = 25)时触发,核心是调用dep.notify()通知依赖更新。
  • 调用它时,dep会遍历自己存储的所有 Watcher 实例,挨个告诉它们 “你依赖的属性变了,赶紧更新”;
  • 新属性的setter里调用:属性修改时自动触发更新;
  • $set最后主动调用一次:确保新增属性能立刻显示在视图上。
    • 收到通知的 Watcher 会执行对应的逻辑:比如视图 Watcher 会刷新页面,watch Watcher 会执行你写的回调函数。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询