介绍几种深拷贝的方法
1.概念
- 深拷贝和浅拷贝是只针对Object和Array这样的复杂类型的
- javascript中存储对象都是存地址的,所以浅拷贝是都指向同一块内存区块,而深拷贝则是另外开辟了一块区域。
- 浅拷贝,也就是说a和b指向了同一块内存,所以修改其中任意的值,另一个值都会随之变化
- 深拷贝,也就是说a和b指向不同的内存,所以修改其中任意的值,另一个值不会随之变化
2.数据类型
- 基本数据类型:number,string,boolean,null,undefined五类;存放在栈(stack)。
- 引用数据类型(Object类)有常规名值对的无序对象{a:1},数组[1,2,3],以及函数等;存放在堆(heap)。
3. 方法
1. 浅拷贝-解构
var o1 = {a: 1, b: 2, c: {cc: 1}}
var o2 = o1
var o = {...o1}
var a1 = [1,2,3]
var a2 = [4,5,6]
var a = [...a1, ...a2]
2. 浅拷贝-直接赋值
var o1 = {a: 1}
var o = o1
var a1 = [1,2,3]
var a = a1
3. 浅拷贝-数组的方法
let a=[0,1,[2,3],4],
let a2 = a.slice();
let a3 = a.concat();
let a1 = a // 情况2
let a4 = [...a] // 情况1
4. 浅拷贝-Object.assign()
Objcet.assign({}, obj) 浅拷贝 属性是有限制的,只拷贝源对象的自身属性,不拷贝继承属性,也不拷贝不可枚举的属性(enumerable: false),也不能拷贝get set属性
可枚举性(enumerable)用来控制所描述的属性,是否将被包括在for...in循环之中。具体来说,如果一个属性的enumerable为false,下面三个操作不会取到该属性。
Object.defineProperty(o, 'b', {value: 2, enumerable: false})
let o1 = {a: 1, b: {bb: 2}}
let o2 = {c: 1, d: {dd: 2}}
const o = Object.assign({}, o1, o2);
5. 深拷贝-JSON.parse(JSON.stringify(obj))
var o1 = {
a: undefined,
b: function(){console.log('11')},
c: /[1-9]/,
d: new Date(),
e: NaN,
f: Infinity,
g: -Infinity,
h: null
}
const o1 = JSON.parse(JSON.stringify(o1));
但是会出现以下情况
- undefined、函数 丢了;
- null,Infinity,-Infinity,NaN变成null;
- 正则变成{};
- new Date() 由对象变成字符串; 原型链没了;
- 对象就是object,所属的类没了
6. 深克隆-jq的方法, $.extend(true, [], arr)
let a=[0,1,[2,3],4],
b=$.extend(true,[],a);
a[0]=1;
a[2][0]=1;
console.log(a,b);
7. 深拷贝-递归
function deepCopy(o) {
if (o instanceof Array) {
var n = [];
for (var i = 0; i < o.length; ++i) {
n[i] = deepCopy(o[i]);
}
return n;
} else if (o instanceof Function) {
var n = new Function("return " + o.toString())();
return n
} else if (o instanceof Object) {
var n = {}
for (var i in o) {
n[i] = deepCopy(o[i]);
}
return n;
} else {
return o;
}
}
8. 深拷贝-MessageChannel-用于两个页面之间的传值
let obj = {
a: 1,
b: {
c: 2,
d: 3
},
f: undefined,
fun: function () {
console.log('fun')
}
}
function deepCopy (obj) {
return new Promise((resolve) => {
const { port1, port2 } = new MessageChannel()
port2.onmessage = ev => resolve(ev.data)
port1.postMessage(obj)
})
}
deepCopy(obj).then((copy) => { // 请记住`MessageChannel`是异步的这个前提!
let copyObj = copy
copyObj.b.c = null
console.log(copyObj, obj)
console.log(copyObj == obj)
})