拷贝有个前提,是针对对象的操作,当想复制一个对象的时候,才存在浅拷贝深拷贝之分!
-
浅拷贝的实现方式
-
Object.assign()
可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
-
lodash的clone方法
-
…操作符
let obj1 = { name: 'Kobe', address:{x:100,y:100}} let obj2= {... obj1} obj1.address.x = 200; obj1.name = 'wade' console.log('obj2',obj2) // obj2 { name: 'Kobe', address: { x: 200, y: 100 } }
-
Array.prototype.concat
let arr = [1,2,3]; let arr2 = [4,5,6];let arr3 = arr.concat(arr2)
let arr = [1, 3, { username: 'kobe' }]; let arr2 = arr.concat(); arr2[2].username = 'wade'; console.log(arr);
-
Array.prototype.slice
let arr = [1, 3, { username: ' kobe' }]; let arr3 = arr.slice(); arr3[2].username = 'wade' console.log(arr); // [ 1, 3, { username: 'wade' } ]
-
-
深拷贝的实现方式
-
JSON.parse(JSON.stringify())
可以处理数组和对象的深拷贝,但是不能处理函数和正则,因为这两者基于这两个函数处理后得到的结果不再是正则/函数
缺点:
- 会忽略undefined
- 会忽略symbol
- 不能序列化函数
- 不能解决循环引用的对象
-
lodash的cloneDeep函数
-
jQuery.extend函数
-
如果所拷贝的对象含有内置对象,但是不包含函数,可以使用
messagechannel
,可以拷贝undefined和循环引用的对象function structuralClone(obj) { return new Promise(resolve => { const { port1, port2 } = new MessageChannel() port2.onmessage = ev => resolve(ev.data) port1.postMessage(obj) }) } var obj = { a: 1, b: { c: 2 } } obj.b.d = obj.b // 注意该方法是异步的 // 可以处理 undefined 和循环引用对象 const test = async () => { const clone = await structuralClone(obj) console.log(clone) } test()
-
-
手写浅拷贝:遍历=>直接等号赋值
// 浅拷贝
let obj1 = {
name : '深深地',
arr : [1,[2,3],4],
};
let obj3=shallowClone(obj1)
obj3.name = "春娇";
obj3.arr[1] = [5,6,7] ; // 新旧对象还是共享同一块内存
// 这是个浅拷贝的方法
function shallowClone(source) {
var target = {};
for(var i in source) {
if (source.hasOwnProperty(i)) {
target[i] = source[i];
}
}
return target;
}
console.log('obj1',obj1) // obj1 { name: '深深地', arr: [ 1, [ 5, 6, 7 ], 4 ] }
console.log('obj3',obj3) // obj3 { name: '春娇', arr: [ 1, [ 5, 6, 7 ], 4 ] }
obj.hasOwnProperty,返回值是一个布尔值,即是否是obj的属性(原型上的是false)
- 深拷贝:遍历,如果是简单数据类型直接赋值,如果是复杂数据类型递归。
// 深拷贝
let obj1 = {
name : '春娇',
arr : [1,[2,3],4],
};
let obj4=deepClone(obj1)
obj4.name = "志明";
obj4.arr[1] = [5,6,7] ; // 新对象跟原对象不共享内存
// 这是个深拷贝的方法
function deepClone(obj) {
if (obj === null) return obj;
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
if (typeof obj !== "object") return obj;
let cloneObj = new obj.constructor();
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key]);
}
}
return cloneObj;
}
console.log('obj1',obj1) // obj1 { name: '春娇', arr: [ 1, [ 2, 3 ], 4 ] }
console.log('obj4',obj4) // obj4 { name: '志明', arr: [ 1, [ 5, 6, 7 ], 4 ] }