浅拷贝和深拷贝
直接赋值:赋值的是引用,被复制的对象仍然指向原对象。
浅拷贝:是对内存地址的复制,让目标对象和源对象都指向同一片内存空间。
深拷贝:拷贝对象的具体内容,内存地址自主分配,拷贝结束后两个对象值都相等,但内存地址不一样。
浅拷贝实现
Object.assign()
,拷贝的是对象的属性的引用,而不是对象本身。
Object,assign(target,...sources)
javascript
let obj1 = {a:{a:'hi',b:21}}
let obj2 = Object.assign({},obj1)
obj2.a.a = 'hello'
console.log(obj2.a.a) //'hello'
注意 Object.assign()
可以处理一层的深度拷贝
javascript
let obj1 = {a:1,b:2,c:3}
let obj2 = Object.assign({},obj1)
obj2.b = 20;
console.log(obj1) //{a:1,b:2,c:3} 未被修改
console.log(obj2) //{a:1,b:20,c:3}
- 展开操作符(
...
)
javascript
let obj1 = {a:1,b:2,c:{d:3}}
let obj2 = {...obj1}
for in
javascript
function shallowClone(initializeObj){
let obj = {};
for(let item in initializeObj){
obj[item] = initializeObj[item];
}
return obj;
}
深拷贝实现
- 手动复制
javascript
var obj1 = { a: 1, b: 2, c: 3 };
var obj2 = { a: obj1.a, b: obj1.b, c: obj1.c };
obj2.b = 20;
console.log(obj1);
// { a: 1, b: 2, c: 3 } <-- 沒被改到
console.log(obj2);
// { a: 1, b: 20, c: 3 }
JSON.stringify
和JSON.parse
用 JSON.stringify
把对象转换成字符串,再用 JSON.parse
把字符串转换成新的对象。
javascript
let obj = {a:1,b:2,c:3}
let newObj = JSON.parse(JSON.stringify(obj))
- 递归拷贝
javascript
function deepClone(obj) {
let objClone = Array.isArray(obj) ? [] : {};
// 判断obj为数组还是对象创建[]/{}
if (obj && typeof obj === 'object') {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
if (obj[key] && typeof obj[key] === 'object') {
objClone[key] = deepClone(obj[key])
//判断obj子元素是否为对象,如果是,递归复制
} else {
objClone[key] = obj[key] //简单复制
}
}
}
}
return objClone
}
- jquery
提供一个$.extend
可以用来做 DeepCopy
javascript
var $ = require('jquery');
var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f);//false
- lodash
lodash
提供 _.cloneDeep
用来做 Deep Copy
javascript
var _ = require('lodash');
var obj1 = { a: 1, b: { f: { g: 1 } }, c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
// false
浏览器自带的全局的 structuredClone()
方法使用结构化克隆算法将给定的值进行深拷贝。(最新的浏览器才可使用,旧的浏览器版本可能不支持该方法)
缺点
- 原型。如果你对一个类的实例使用
structuredClone()
,你会得到一个普通的对象作为返回值,因为结构化克隆抛弃了对象的原型链。 - 函数。如果你的对象包含函数,它们将被悄悄地丢弃。
- 不可克隆的对象。有些值是不可结构化克隆的,最明显的是
Error
和DOM
节点。这将导致structuredClone()
被抛出。