新增对象属性、数组索引赋值为什么可能不更新?

先理解原理和示例,再练习完整口述与追问。

Vue2 无法自动侦测所有新增 / 删除属性和数组索引、length 的直接修改。预声明状态;对已响应式的嵌套对象可用 $set / $delete;数组可用 splice 或替换。不要事后随意给实例追加根级状态。

Vue2 初始化时只能对当时存在的对象键逐个定义访问器,因此直接新增键不会自动拥有对应 setter。数组下标和 length 直接变化不走 Vue2 封装的数组通知路径,但 push、splice 等被重写的方法会通知。Vue.set 对已有键可赋值,对数组索引用 splice,对合适的已观察对象新增键则定义响应式属性并通知对象层依赖。

js
// Vue2 组件 methods 中,user 和 rows 已在 data 声明
this.$set(this.user, 'nickname', 'Lin')
this.rows.splice(0, 1, { id: 1, name: 'new' })
this.user = { ...this.user, city: 'Shanghai' }

最后一种是给已声明的 user 根字段设置新对象,新对象会被观察;它不同于直接给实例增加一个未声明根字段。

不要在 Vue3 中继续套用“所有新增键都必须 $set”的结论。初始化就能确定的表单字段应先声明;更新正常却未显示时,还要检查模板实际读取的是不是同一对象。

Vue2 在观察对象时只为当时存在的属性建立 getter/setter,之后直接新增属性不会自动进入这条链路。数组直接写下标或 length 也不会经过它处理过的数组方法。我会先在 data 声明完整状态;给已观察的嵌套对象加字段用 this.$set,删字段用 this.$delete;修改数组元素用 splice,或者生成新数组再赋值。接口整对象替换时,只要目标字段本身已响应式,新对象也会被继续观察。

面试官可能继续问追问与完整解答展开收起

为什么给接口对象补字段不生效?Object.assign 到旧对象和替换为新对象有什么差异?Vue2 官方响应式说明

Object.assign(oldObject, data) 会给旧对象原地添加属性,这些新增字段不一定被观察;this.form = Object.assign({}, this.form, data) 是通过已有 form 的 setter 替换对象,新对象会被观察。单个动态字段也可以用 this.$set(this.form, key, value)。