1.浅拷贝
简单的来说,浅拷贝就是增加了一个'指针'指向已存在的内存(JavaScript并没有指针的概念,这里只是用于辅助说明),浅拷贝只是拷贝了内存的地址,子类的属性指向的是父类属性的内存地址,当子类的属性修改后,父类的属性也会随之被修改。我们来看下一个例子:
var arrayA = [ 1,2,3,4,5 ]; var arrayB = arrayA ;这就是一个简单的浅拷贝的例子,首先声明了一个arrayA数组,然后又声明一个arrayB数组,并把arrayA数组赋值给arrayB数组,然后往arrayA里push一个元素,结果arrayB里的元素也跟着改变了,这就是浅拷贝。下面我给出一张图来辅助理解:var str = 'hello' arrayA.push(str) ;console.log(arrayA);// [1, 2, 3, 4, 5, "hello"]console.log(arrayB);// [1, 2, 3, 4, 5, "hello"]
2.深拷贝
深拷贝就是增加一个“指针”,并申请一个新的内存,并且让这个新增加的“指针”指向这个新的内存地址,使用深拷贝,在释放内存的时候就不会像浅拷贝一样出现重复释放同一段内存的错误,当我们需要复制原对象而又不能修改元对象的时候,深拷贝就是一个,也是唯一的选择。我们来看一下例子:
var arrayA = [ 1,2,3,4,5 ]; var arrayB = [] ; arrayA.forEach ( function (element){ arrayB.push(elemnt); }) var str = 'hello' arrayA.push(str) ; console.log(arrayA);// [1, 2, 3, 4, 5, "abc"] console.log(arrayB);// [1, 2, 3, 4, 5]这似乎是解决了浅拷贝所存在的问题。但是我们修改一下
var arrayA = [ 1,2,3,4,5 ]; var arrayB = [] ;var obj = {name : 'unix'} arrayA.push(obj) ;arrayA.forEach(function (element){ arrayB.push(element);})
arrayB[5].name = 'Alex'console.log(arrayA);// [1, 2, 3, 4, 5, {name:'Alex'}]
console.log(arrayB);// [1, 2, 3, 4, 5, {name:'Alex'}]
这里修改arrayB中的元素的时候,arrayA中的元素却跟着改变,是为什么呢?我们来看下面这张图辅助理解一下:
这里的arrayA和arrayB中的最后一个元素,这个元素是一个对象,指向的是同一段内存地址,所以当修改其中一个元素对象的值时,导致了另一个的值也跟着发生改变,但是如果新增加的元素不是一个对象,而是一个字符串,或者一个数字,这时候是没问题的。有问题我们是需要去解决的,对于第一种情况,我们使用同样的方式去解决它。既然新增加的元素是一个字符串或者一个数字的情况下,改变一个元素的值不会引发另一个元素的值的改变,所以我们就使用这种方式去解决,解决方案如下所示:
function copy( sourceObj , c) { var c = c || ( Array.isArray(sourceObj) ? [ ] : {} ); for (var i in sourceObj) { if (typeof sourceObj[i] === 'object') { c[i] = Array.isArray(sourceObj[i]) ? [] : {}; copy (sourceObj[i], c[i]); } else { c[i] = sourceObj[i]; } } return c; } var arrayA = [1,2,3,4,5]; var obj = {name:'Alex'}; arrayA.push(obj) var arrayB = []; copy(arrayA,arrayB); arrayB[5].name = 'Tom' console.log(arrayA);// [1, 2, 3, 4, 5, "Alex"] console.log(arrayB);// [1, 2, 3, 4, 5, "Tom"]我们先定义一个copy函数,传入两个参数,第一个参数是原对象,第二个参数是复制的对象,我们循环原对象,看原对象中的元素的类型是否是对象(Object),如果是的话我们再使用递归调用,copy这个对象,如果不是对象,直接赋值。最后返回copy后的对象,也就是这里的arrayB,当我们修改arrayB中的name的值时,arrayA里的值是不会跟着发生改变的。这里涉及到了递归调用,有不明白的童鞋可以看下递归相关的资料。这就完成了对一个对象的深拷贝。
浅拷贝比较容易理解,当然深拷贝也是容易理解的,只是得注意拷贝上面说的那种情况。就没问题了。有任何问题,欢迎提问