
🤍 前端开发工程师、技术日更博主、已过CET6
🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1
🕠 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》、《前端求职突破计划》
🍚 蓝桥云课签约作者、上架课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入门到实战全面掌握 uni-app》
文章目录
在 Vue.js 开发中,$set 是一个非常实用的方法,用于确保对象或数组的响应式更新。虽然 Vue 的响应式系统能够自动追踪对象和数组的变化,但在某些情况下,直接修改对象或数组可能会导致 Vue 的响应式系统无法检测到这些变化。本文将详细介绍 $set 的使用场景、实现原理以及如何在实际开发中有效利用这一方法。
一、引言
Vue.js 是一个渐进式框架,通过响应式数据绑定和虚拟 DOM 实现高效的页面更新。Vue 的响应式系统基于 Object.defineProperty(Vue 2)或 Proxy(Vue 3)实现,能够自动追踪对象和数组的变化。然而,在某些情况下,直接修改对象或数组可能会导致 Vue 的响应式系统无法检测到这些变化。$set 方法提供了一种解决方案,确保对象或数组的响应式更新。
二、Vue 的响应式系统
(一)Vue 2 的响应式系统
在 Vue 2 中,Vue 的响应式系统基于 Object.defineProperty 实现。通过 Object.defineProperty,Vue 为对象的每个属性定义了 getter 和 setter,从而实现响应式更新。然而,Object.defineProperty 有一些局限性:
- 无法检测对象属性的动态添加或删除:直接添加或删除对象的属性不会触发响应式更新。
- 无法检测数组索引的变化:直接通过索引修改数组元素不会触发响应式更新。
(二)Vue 3 的响应式系统
在 Vue 3 中,Vue 的响应式系统基于 Proxy 实现。Proxy 提供了更强大的拦截功能,能够检测对象属性的动态添加或删除,以及数组索引的变化。然而,在某些情况下,直接修改对象或数组仍然需要使用 $set 方法。
三、$set 的使用场景
(一)动态添加对象属性
在 Vue 2 中,直接添加对象属性不会触发响应式更新。$set 方法可以确保动态添加的属性是响应式的。
export default {
data() {
return {
user: {
name: 'John'
}
};
},
methods: {
addAge() {
this.$set(this.user, 'age', 30);
}
}
};
在这个例子中,addAge 方法通过 $set 动态添加了 age 属性,并确保它是响应式的。
(二)动态删除对象属性
在 Vue 2 中,直接删除对象属性不会触发响应式更新。$set 方法可以确保动态删除的属性是响应式的。
export default {
data() {
return {
user: {
name: 'John',
age: 30
}
};
},
methods: {
removeAge() {
this.$set(this.user, 'age', undefined);
}
}
};
在这个例子中,removeAge 方法通过 $set 动态删除了 age 属性,并确保它是响应式的。
(三)修改数组元素
在 Vue 2 中,直接通过索引修改数组元素不会触发响应式更新。$set 方法可以确保数组元素的修改是响应式的。
export default {
data() {
return {
items: [1, 2, 3]
};
},
methods: {
updateItem(index, value) {
this.$set(this.items, index, value);
}
}
};
在这个例子中,updateItem 方法通过 $set 修改了数组的第 index 个元素,并确保它是响应式的。
(四)Vue 3 中的 $set
在 Vue 3 中,虽然 Proxy 提供了更强大的拦截功能,但在某些情况下,直接修改对象或数组仍然需要使用 $set 方法。例如,当使用 Vue.observable 或 reactive 创建响应式对象时,$set 方法仍然适用。
import { reactive } from 'vue';
export default {
data() {
return {
user: reactive({
name: 'John'
})
};
},
methods: {
addAge() {
this.$set(this.user, 'age', 30);
}
}
};
在这个例子中,addAge 方法通过 $set 动态添加了 age 属性,并确保它是响应式的。
四、$set 的实现原理
(一)Vue 2 中的 $set
在 Vue 2 中,$set 方法通过 Object.defineProperty 重新定义对象的属性,确保新属性是响应式的。
Vue.prototype.$set = function(target, propertyName, value) {
if (target._isVue || (process.env.NODE_ENV !== 'production' && isReservedProp(propertyName))) {
process.env.NODE_ENV !== 'production' && warn(
`Avoid adding reactive properties to a Vue instance or its root $data ` +
`at runtime - declare it upfront in the data option.`);
return;
}
if (!isObject(target)) {
process.env.NODE_ENV !== 'production' && warn(`Cannot set reactive property on undefined, null, or primitive value: ${(target: any)}"`);
return;
}
const ob = target.__ob__;
if (Array.isArray(target) && isValidArrayIndex(propertyName)) {
target.length = Math.max(target.length, Number(propertyName));
target.splice(propertyName, 1, value);
return value;
}
if (propertyName in target && !(propertyName in Object.prototype)) {
target[propertyName] = value;
return value;
}
if (ob) {
ob.convert(target, propertyName);
}
defineReactive(target, propertyName, value);
return value;
};
(二)Vue 3 中的 $set
在 Vue 3 中,$set 方法通过 Proxy 重新定义对象的属性,确保新属性是响应式的。
import { reactive, isReactive } from 'vue';
export default {
methods: {
$set(target, property, value) {
if (!isReactive(target)) {
target = reactive(target);
}
target[property] = value;
}
}
};
五、$set 的注意事项
(一)性能开销
虽然 $set 方法可以确保对象或数组的响应式更新,但频繁使用 $set 方法可能会增加性能开销。因此,应尽量避免不必要的 $set 调用。
(二)Vue 3 的优化
在 Vue 3 中,Proxy 提供了更强大的拦截功能,能够检测对象属性的动态添加或删除,以及数组索引的变化。因此,在 Vue 3 中,$set 方法的使用场景相对较少。
(三)数据结构变化
$set 方法依赖于 Vue 的响应式系统。如果数据结构发生变化(例如动态添加或删除属性),Vue 可能无法正确更新响应式状态。
六、总结
Vue 的 $set 方法是一个非常实用的工具,用于确保对象或数组的响应式更新。在 Vue 2 中,$set 方法通过 Object.defineProperty 重新定义对象的属性,确保新属性是响应式的。在 Vue 3 中,虽然 Proxy 提供了更强大的拦截功能,但在某些情况下,直接修改对象或数组仍然需要使用 $set 方法。通过合理使用 $set 方法,可以优化代码结构并提升项目的性能和可维护性。
861

被折叠的 条评论
为什么被折叠?



