Object.assign基础,JS里它是做什么的?
不少刚上手Vue2的同学,总会在项目里看到Object.assign的身影,却不太明白它在Vue生态里到底咋用、能解决啥问题,这篇文章就从基础到实战,把Vue2里Object.assign的用法、关联知识点、避坑技巧一次性讲透,帮你真正搞懂它的价值~
先回到JavaScript本身,Object.assign是ES6引入的对象操作方法,作用是把多个“源对象”的属性合并到“目标对象”里,最后返回更新后的目标对象,语法长这样:Object.assign(目标对象, 源对象1, 源对象2, ...)
。
举个简单例子:
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
console.log(target); // 输出 {a:1, b:2, c:3}
这里要注意个关键特性——浅拷贝,如果源对象里有嵌套对象( x: { y: 1 } }),合并后目标对象里的嵌套对象只是“引用”,不是新对象,修改源对象的嵌套属性,目标对象的对应属性也会跟着变。
const source = { x: { y: 1 } };
const target = Object.assign({}, source);
source.x.y = 2;
console.log(target.x.y); // 输出2,因为共享引用
所以Object.assign适合扁平对象的合并,如果要深拷贝嵌套对象,得用JSON.parse(JSON.stringify())或者lodash的cloneDeep这类方法~
Vue2响应式原理和Object.assign有啥关联?
Vue2的“响应式魔法”靠的是Object.defineProperty——初始化时,它会对data里的对象属性逐个“劫持”,这样数据变化时能自动更新视图,但有个隐藏限制:新增属性不会自动变成响应式。
比如这样写,页面根本不会更新:
data() {
return {
user: { name: '张三' }
}
},
methods: {
addAge() {
this.user.age = 20; // 直接新增属性,Vue没劫持,视图不更新
}
}
这时候Object.assign就能派上用场了!它能生成新对象替换原对象,让Vue检测到“引用变化”,从而重新对新对象的属性进行劫持,正确写法是这样:
methods: {
addAge() {
this.user = Object.assign({}, this.user, { age: 20 });
}
}
原理是:原来的user是旧引用,合并后生成的{...}是新引用,Vue监测到user的引用变了,就会对新user的所有属性(包括新增的age)重新做响应式劫持,这样视图就能跟着更新啦~
Vue2开发中Object.assign的典型使用场景
理解了基础和响应式关联,再看它在实际项目里的高频场景,你会发现它真的很实用~
表单数据整理:合并默认值与用户输入
做表单时,经常需要给用户输入加一些“默认字段”(比如提交状态、数据类型),用Object.assign合并超方便:
// 组件data里的默认值
defaultForm: {
type: 'article',
status: 'draft',
submitTime: ''
},
// 用户输入的临时数据
tempForm: { '我的第一篇文章',
content: '正文内容...'
},
// 提交前合并
const finalForm = Object.assign({}, this.defaultForm, this.tempForm);
// finalForm里就有type、status、title、content等所有字段,直接传给接口
这样既保证默认字段不丢,又能整合用户输入,而且如果finalForm是响应式数据(比如在data里),替换后视图也能及时更新~
给响应式对象“安全”新增属性
回到之前的“响应式失效”问题,只要涉及给对象新增属性,用Object.assign生成新对象替换,就能保证属性响应式,比如给用户信息加地址:
data() {
return {
user: { name: '李四', email: 'lisi@example.com' }
}
},
methods: {
setAddress() {
this.user = Object.assign({}, this.user, {
address: '上海市浦东新区'
});
}
}
点击按钮执行setAddress后,页面上{{user.address}}就能正常显示,因为新user是响应式的~
组件配置项合并:props默认值 + 用户传入值
开发通用组件时,常需要合并“默认配置”和“用户自定义配置”,比如一个弹窗组件,默认配置和用户传的props合并:
// 组件内部默认配置
const defaultConfig = {
width: '50%',
mask: true,
closeOnClickMask: false
};
// 用户通过props传入的配置
const userConfig = this.props.config;
// 合并后作为最终配置
const finalConfig = Object.assign({}, defaultConfig, userConfig);
这样用户传的配置会覆盖默认值,没传的保留默认,既灵活又可控~
替代重复的对象赋值,让代码更简洁
如果不用Object.assign,给对象加多个属性得写一堆this.obj.a = ... this.obj.b = ...,代码冗余,用assign合并成一行,清爽很多:
// 冗余写法
this.obj.name = '王五';
this.obj.age = 30;
this.obj.gender = '男';
// 简洁写法
this.obj = Object.assign({}, this.obj, {
name: '王五',
age: 30,
gender: '男'
});
而且后者还能保证响应式,一举两得~
用Object.assign容易踩的坑有哪些?
好用归好用,要是不注意细节,也容易掉坑里,这几个常见陷阱得警惕~
浅拷贝导致的“意外修改”
前面说过,Object.assign是浅拷贝,嵌套对象共享引用,比如做数据备份时,以为复制了一个新对象,结果修改备份影响了原数据:
const original = { x: { y: 1 } };
const backup = Object.assign({}, original);
backup.x.y = 2;
console.log(original.x.y); // 输出2,原数据被改了!
如果业务里需要“完全独立”的副本,千万别用Object.assign,换成深拷贝方法更安全~
响应式“假更新”:没替换对象引用
很多同学会犯这个错:想给对象加新属性,却没把合并后的新对象赋值回去,导致响应式失效。
// 错误写法!
methods: {
addAge() {
Object.assign(this.user, { age: 20 }); // 直接修改原对象,没换引用
}
}
这时候age确实被加到user里了,但因为user的引用没变化,Vue没检测到数据变化,视图不会更新。一定要记住:必须把合并后的新对象赋值给原来的响应式变量,像这样:
this.user = Object.assign({}, this.user, { age: 20 });
和Vue.set搞混:场景要分清
Vue提供的this.$set
(或Vue.set)也能给对象加响应式属性,它和Object.assign有啥区别?
- Vue.set:直接给已有对象新增单个属性并让它响应式,不需要替换整个对象,语法:
this.$set(目标对象, '属性名', 值)
,适合只加一个属性的场景。 - Object.assign:适合合并多个属性,或者需要替换整个对象结构的场景,比如一次加age、gender、address三个属性,用assign更高效。
举个对比例子:
// 只加一个age,用Vue.set
this.$set(this.user, 'age', 20);
// 同时加age、gender,用Object.assign
this.user = Object.assign({}, this.user, {
age: 20,
gender: '女'
});
根据场景选工具,效率更高~
Object.assign和扩展运算符(...)在Vue2里怎么选?
ES6的扩展运算符(...)也能合并对象,比如{...oldObj, ...newObj}
,它和Object.assign有啥区别?
本质上,两者都是浅拷贝,作用几乎一样,语法上扩展运算符更简洁,Object.assign能支持多个源对象(比如合并三个对象),在Vue2里,它们的核心作用都是生成新对象替换原响应式对象,从而触发更新。
比如给user加age,用扩展运算符可以这样写:
this.user = { ...this.user, age: 20 };
和Object.assign的写法效果完全一致,所以选哪个看团队代码风格,或者个人偏好~ 但要注意,它们都解决不了深拷贝嵌套对象的问题,这点和Object.assign是一样的~
实战案例:用Object.assign解决响应式失效问题
光说不练假把式,看个真实开发中的场景,你就明白它多实用了~
案例:用户信息编辑页,新增地址不更新
需求:用户信息页原本只有name和email,现在要加address字段,输入后页面实时显示。
❌ 错误写法(响应式失效):
<template>
<div>
<p>姓名:{{ user.name }}</p>
<p>邮箱:{{ user.email }}</p>
<p>地址:{{ user.address }}</p>
<button @click="addAddress">设置地址</button>
</div>
</template>
<script>
export default {
data() {
return {
user: { name: '赵六', email: 'zhaoliu@example.com' }
}
},
methods: {
addAddress() {
this.user.address = '广州市天河区'; // 直接新增,无响应式,页面不更新
}
}
}
</script>
✅ 正确写法(用Object.assign替换对象):
methods: {
addAddress() {
this.user = Object.assign({}, this.user, {
address: '广州市天河区'
});
}
}
点击按钮后,address就能正常显示了,原理是新user对象替换了旧引用,Vue重新劫持所有属性,address变成响应式~
案例:合并表单默认值,提交更省心
需求:发布文章时,用户填标题和内容,系统自动加type、status等默认字段,然后提交。
<template>
<form @submit.prevent="handleSubmit">
<input v-model="tempForm.title" placeholder="标题" />
<textarea v-model="tempForm.content" placeholder="内容"></textarea>
<button type="submit">提交</button>
</form>
</template>
<script>
export default {
data() {
return {
defaultForm: {
type: 'article',
status: 'pending',
createTime: new Date().getTime()
},
tempForm: {
title: '',
content: ''
}
}
},
methods: {
handleSubmit() {
// 合并默认值和用户输入
const finalForm = Object.assign({}, this.defaultForm, this.tempForm);
// 调用接口提交finalForm
console.log(finalForm);
// 这里能看到type、status、createTime、title、content都有值
}
}
}
</script>
这样提交时数据完整,还不用手动一个个加默认字段,效率拉满~
掌握Object.assign,Vue2开发更丝滑
Object.assign在Vue2里的核心价值,是通过“生成新对象替换原对象”,解决响应式对象新增属性/合并数据时的视图更新问题,记住这几点,你就能用得顺手:
- 它是JS的浅拷贝合并方法,适合扁平对象操作;
- 和Vue2响应式结合时,必须替换原响应式对象的引用才能触发更新;
- 浅拷贝有嵌套对象共享引用的坑,深拷贝别用它;
- 和Vue.set、扩展运算符按需配合,场景不同选不同工具。
把这些知识点吃透,以后遇到“对象属性更新视图不刷新”“多对象合并”这类问题,你就知道该怎么用Object.assign四两拨千斤啦~ 要是还有疑问,评论区随时交流~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。