JavaScript 对象怎么克隆
日常写代码的时候,你肯定碰过这种麻烦:给一个对象赋值给新变量,改了新变量里的内容,原来的对象也跟着变了。比如你给朋友做了个购物清单对象,自己复制一份打算加零食,结果原来的清单也多了零食——这不是朋友改的,是你操作出了问题。这背后藏着JavaScript里的“对象克隆”坑,咱们一步步说清楚。
为啥直接赋值不算克隆?
先拿生活例子讲:你写了一张购物清单,纸的左边列了3件东西,你在右边又描了一遍一模一样的字——这叫“抄内容”。但如果是你朋友把自己的购物清单直接递给你,说“你自己看”,你改了他清单上的字,他的清单肯定也变,因为你们用的是同一张纸。

JavaScript里给对象赋值,就像递同一张纸:
`javascript
// 原对象
const originalList = { fruit: '苹果', price: 10 };
// 只是赋值,指向同一张纸
const copyList = originalList;
copyList.fruit = '香蕉';
console.log(originalList.fruit); // 输出香蕉,原对象被改了
`
这根本不是克隆,只是“共享同一份数据”。要真克隆,得做一张完全独立的新纸。
浅克隆:适合“内容全是基础类型”的情况
如果你的对象里没有嵌套的子对象,只有字符串、数字这种简单数据,浅克隆就够用——相当于重新抄一张全是字的新纸,改哪张都不影响。
有两个很简单的方法:
- 用
Object.assign():把原对象的属性挨个复制到新对象里,比如:
`javascript
const original = { name: '小明', age: 25 };
const shallowCopy = Object.assign({}, original);
shallowCopy.age = 26;
console.log(original.age); // 还是25,原对象没变
`
- 用扩展运算符
...:写法更简洁,效果和Object.assign()一样:
`javascript
const shallowCopy = {...original};
`
但要注意,浅克隆只复制“表层”的属性,要是里面有嵌套的子对象,比如购物清单里还列了“零食清单”这个子对象,那复制过来的还是同一张子对象的纸。
深克隆:解决嵌套对象的“共享坑”
要是原对象有嵌套的子对象,浅克隆就失效了——还是用购物清单的例子:你复制的清单里,“零食”那栏的子对象,和原清单的“零食”用的是同一张纸,改这个子对象,原对象还是会变。
比如:
`javascript
const originalList = {
fruit: '苹果',
snack: { type: '薯片', price: 8 } // 嵌套的子对象
};
const shallowCopy = {...originalList};
shallowCopy.snack.type = '巧克力';
console.log(originalList.snack.type); // 变成巧克力了,子对象还是共享的
`
这时候就需要深克隆——相当于把整个清单,包括里面的每一张子纸,都重新抄一遍,所有层级的内容都是独立的。
日常写代码,有个简单的深克隆方法,就是用JSON.parse()搭配JSON.stringify():把原对象转成JSON字符串(相当于把所有内容拆成纯文字),再转成新对象,这样就完全是独立的了:
`javascript
const deepCopy = JSON.parse(JSON.stringify(originalList));
deepCopy.snack.type = '饼干';
console.log(originalList.snack.type); // 还是薯片,完全独立
`
这个方法适合大部分普通对象,但有个小缺点:如果对象里有函数、undefined或者特殊类型(比如日期对象),JSON.stringify会把这些内容直接忽略,克隆出来就会丢数据。
要是需要处理特殊类型的对象,比如带日期的日程表,就得用专门的深克隆方法,或者自己写个简单的递归函数——递归就是“自己调用自己”,挨个复制每个层级的属性,遇到子对象就再复制一次,保证所有层级都独立。
日常开发里,要不要用深克隆、浅克隆,全看你的场景:只是复制个简单的用户信息,用浅克隆就够;要是处理有嵌套数据的表单、配置对象,就得用深克隆,避免不小心改到原数据。