拷贝也即是复制。那么深拷贝和浅拷贝呢?
在JavaScript这门语言中,数据类型分为两大类:基本数据类型和复杂数据类型。而所有引用类型(Array、Date、RegExp、Function、基本包装类型(Boolean、String、Number)、Math等)都是Object类型的实例对象,赋值实际是内存地址的赋值。
基本数据的的拷贝也就是把值赋值给了另一个变量,改变新的变量对原数据是没有影响的。
但是引用数据类型的拷贝不一样,我们知道引用数据类型存储的是内存中的存储地址,所以在拷贝的时候实际是把内存地址赋值给了另一个数据,所以当我们在把新数据改变的时候,原来的数据也会受影响。
var a = {
"name": "title",
"description": "Hello World!"
}
var b = a;
b.description = "Hello Javascript!";
console.log(a);
console.log(b);
这时候a的值也跟着变化,可是很多时候我们不想对新的对象的改变影响到原来的对象。
那么很多人想到了用for,把所有属性遍历一遍,赋值过去
var b = {}
function copy(o){
var o1 = {};
for( var x in o){
o1[x] = o[x]
}
return o1;
}
b = copy(a);
这样好像实现了,可是如果对象的属性又是一个对象呢,这个方法就不起作用了。这时候里面的对象属性值的改变又会改变原有的对象。需要我们继续遍历,当然有人想到了用递归,对确实是递归可以实现。后面我们再说到递归实现。
对象的深拷贝,简单的理解也就是新的对象属性值的改变不会对原对象造成任何影响。
当然浅拷贝就是会影响咯。
下面我们来介绍几种对象拷贝的方法
1、直接用for来赋值,也就是前面我们用的copy()函数,当然这个只能实现浅拷贝。但是对于对象属性值都是基本类型的可以使用。
2、Object.assign()
Object.assign()是ES6方法,现在基本都支持。可以查看使用方法。
Object.assign() 方法用于把一个或多个源对象的可枚举属性值复制到目标对象中,返回值为目标对象。
语法 Object.assign(target, ...sources)
可以把多个对象复制到目标对象中。
我们可以试验前面的例子
var b = Object.assign( {} , a);
我们这样实现对象的拷贝,改变b的值发现a的值不会变化,但是如果我们把a的其中的属性换成对象的话,这时候结果跟用for是一样的。
所以这样也只实现了对象的浅拷贝。
3、那么现在我们就用上面的说的用递归来遍历对象的属性实现
那么怎么判断对象的属性是对象或者数组呢。
判断对象很简单 typeof即可
判断数组 ① a instanceof Array ② Array.isArray(a) ③ a.constructor === Array
那么在遍历对象时就可以判断属性值是否为对象,如果为对象调用自己。如果不是直接赋值。
function deepCopy(o){
var o1 = {};
for ( var x in o) {
if ( typeof(o[x]) === "object") {
o1[x] = o[x].constructor === Array ? [] : {};
o1[x] = deepCopy(o[x]);
} else {
o1[x] = o[x];
}
}
return o1;
}
var b = deepCopy(a);
这样的时候就实现了深拷贝,怎么改变新的对象都不会对原来对象有影响。
4、JSON方法。
思路将对象转换成字符串也就是基本类型,这时候赋值过去在把字符串转换为对象。
var b = JSON.parse(JSON.stringify(a));
这种方法也能实现对象的深拷贝。