JavaScript对象拷贝

JavaScript对象拷贝

现有一个对象obj需要将他复制到一个名为obj2的变量上:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const obj = {
a: 1,
b: "string",
c: BigInt(1),
d: Symbol("symbol"),
e: { a: 1, b: 2 },
f: [1, 2, 3],
g: new Date(),
h: /regex/,
i: null,
j: undefined,
k: NaN,
l: Infinity,
m: -Infinity,
n: true,
o: false,
p: () => {},
};

方式一:直接赋值

1
const obj2 = obj;
  • 优点
    • 简单
  • 缺点
    • 不是深拷贝(会造成引用传递)
1
2
obj2.a = 2;
console.log(obj.a); // 2

方式二:JSON.parse(JSON.stringify(obj))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const obj1 = JSON.parse(JSON.stringify(obj));
// obj内有BigInt会直接报错
// TypeError: Do not know how to serialize a BigInt
// 将BigInt去掉在调用得到如下的值:
{
a: 1,
b: 'string',
e: { a: 1, b: 2 },
f: [ 1, 2, 3 ],
g: '2020-04-21T07:32:05.848Z',
h: {},
i: null,
k: null,
l: null,
m: null,
n: true,
o: false
}
  • 优点
    • 简单
    • 为深拷贝不会造成引用传递
  • 缺点
    • 无法拷贝BigInt(会直接报错)
    • undefined会被过滤掉
    • 函数会被过滤掉
    • Symbol会被过滤掉
    • 日期会被格式化为字符串
    • 正则表达式会被置为空对象
    • NaN会被过滤掉
    • Infinity会被过滤掉
    • -Infinity会被过滤掉

方式三:Object.assign({},obj)"

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const obj2 = Object.assign({}, obj);
// result:
{
a: 1,
b: 'string',
d: Symbol(symbol),
e: { a: 1, b: 2 },
f: [ 1, 2, 3 ],
g: 2022-07-16T07:33:59.629Z,
h: /regex/,
i: null,
j: undefined,
k: NaN,
l: Infinity,
m: -Infinity,
n: true,
o: false,
p: [Function: p]
}
  • 优点
    • 简单
  • 缺点
    • 只有第一层深拷贝,第二层以上的拷贝都会造成引用传递
1
2
3
4
obj2.a = 2;
console.log(obj.a); // 1
obj2.e.a = "change";
console.log(obj.e.a); // "change"

方式三:扩展运算符(...)

1
const obj2 = { ...obj };

效果同方式二

方式四:递归拷贝

循环obj每一项及子项,判断类型然后复制。
可以使用lodashcloneDeep方法链接

深浅拷贝

深浅拷贝只是针对引用类型的,因为引用类型是存放在堆内存中,在栈地址有一个或者多个地址来指向推内存的某一数据。

浅拷贝

被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象。

浅拷贝仅仅复制所考虑的对象,而不复制它所引用的对象,如果你修改了“副本”的值,那么原来的对象也会被修改。

深拷贝

深拷贝是一个整个独立的对象拷贝,深拷贝会拷贝所有的属性,并拷贝属性指向的动态分配的内存。当对象和它所引用的对象一起拷贝时即发生深拷贝。深拷贝相比于浅拷贝速度较慢并且花销较大。

深拷贝把要复制的对象所引用的对象都复制了一遍。如果你修改了“副本”的值,那么原来的对象不会被修改,两者是相互独立的。


JavaScript对象拷贝
https://www.shaohang.xin/2020/04/22/technical/javascript/clone-deep/
作者
少航
发布于
2020年4月22日
许可协议