javascript的基本类型包括字符串、数字、布尔、数组、对象、Null、Undefined。基本类型和对象最大的不同在于他们的传值方式:基本类型是按值传递的,但是对象是按引用传值的.
基本类型:
var a = 1;
var b = a;
b = 2;
console.log(a); //1
console.log(b); //2
从上面的例子可以看出,由于是按值传递,所以改变b的值不会改变a
如果是对象,由于是按引用传值,类似的做法会改变另外一个相关对象的属性,这就是浅复制(新旧对象公用一块内存空间):
var obj1 = { a:1 , b:2 };
var obj2 = obj1;
obj.a = 3;
console.log(obj1); //{ a:3 , b:2 }
console.log(obj2); //{ a:3 , b:2 }
console.log(obj1 === obj2); //true
如果不让原本obj1对象属性,那么就是深复制(新旧对象使用不同内存空间)
简单实现:
var obj2 = { a:obj1.a , b:obj1.b };
obj2.a = 3;
console.log(obj1); //{ a:1 , b:2 }
console.log(obj2); //{ a:3 , b:2 }
console.log(obj1 === obj2); //false
这种方法可以实现深度复制,但是略显臃肿,而且如果有嵌套对象(有多层对象)实现起来就更麻烦了,比如:
var obj1 = { grade : { math : 100 , Chinese : 90 } };
var obj2 = { grade : obj1.grade };
obj2.grade.math = 120;
console.log(obj1); // { grade : { math : 120 , Chinese : 90 } };
var obj2 = { grade : obj1.grade.math , grade : obj1.grade.Chinese }; //这样才能深度复制
深度复制除了上面方法,还可以用其他方法实现
1.ES6的Object.assign
ES6引入了一个Object.assign的新函数,可以把任意个源对象自身的可枚举属性拷贝给目标对象,然后再返回目标对象。不过其进行的是浅复制i,复制的是对象属性的引用
不过,它还是可以实现一层的深度复制,比起前面的手动复制要简单一点,比如
var obj1 = { a:1 , b:2 };
var obj2 = Object.assign( {} , obj1 };
obj.a = 3;
console.log(obj1); //{ a:1 , b:2 }
console.log(obj2); //{ a:3 , b:2 }
2.JSON.stringify+JSON.parse
前面提到了,js的基本类型是按值传递的,那么既然有这样的特性我们完全可以将对象转换成字符串,然后再用parse解析成新对象
var obj1 = { a:1 , b:2 };
var obj2 = JSON.parse(JSON.stringify(obj1));
obj.a = 3;
console.log(obj1); //{ a:1 , b:2 }
console.log(obj2); //{ a:3 , b:2 }
console.log(obj1 === obj2); //false
不过,这个方法还是有缺陷,只有可以转换成JSON格式的对象才可以使用,RegExp对象是无法通过该方法实现深度复制的,函数也无法使用
3.递归拷贝
function deepClone(initalObj,finalObj){
var obj = finalObj || {};
for(var i in initalObj){
var prop = initalObj[i];
if(prop === obj)
continue;
if(typeof prop === 'object'){
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop,obj[i]);
}else{
obj[i] = prop;
}
}
return obj;
}
4.Object.create(initalObj)
注意和前面递归方法的区别
function deepClone(initalObj,finalObj){
var obj = finalObj || {};
for(var i in initalObj){
var prop = initalObj[i];
if(prop === obj)
continue;
if(typeof prop === 'object'){
obj[i] = (prop.constructor === Array) ? [] : Object.create(prop);
arguments.callee(prop,obj[i]);
}else{
obj[i] = prop;
}
}
return obj;
}
5.slice和concat巧妙的方法
实质上这也是浅复制,只不过返回一个浅复制了原数组中的元素的一个新数组
var arr1 = [1, 2, 3, 4],
arr2 = arr1.slice(0),
arr3 = arr1.concat();
console.log(arr1, arr2, arr3);
arr2[2] = 10;
arr3[2] = 11;
console.log(arr1[2], arr2[2], arr3[2]);
> 1,2,3,4, 1,2,3,4, 1,2,3,4
> 3, 10, 11
console.log( arr1 === arr2 ); //false
console.log( arr1 === arr3 ); //false
又比如:
var array = [1, [1,2,3], {name:"array"}];
var array_concat = array.concat();
var array_slice = array.slice(0);
array_concat[1][0] = 5; //改变array_concat中数组元素的值
console.log(array[1]); //[5,2,3]
console.log(array_slice[1]); //[5,2,3]
array_slice[2].name = "array_slice"; //改变array_slice中对象元素的值
console.log(array[2].name); //array_slice
console.log(array_concat[2].name); //array_slice
jQuery提供了一个$.extend方法可以做深度复制
var arr1 = [1, 2, [3, 4], {a: 5, b: 6}, 7],
arr2 = $.extend(true, [], arr1);
console.log(arr1, arr2);
arr2[1] = 10;
console.log(arr1, arr2);
还有一个叫lodash的函数库的_.cloneDeep方法可以实现深度复制
参考:http://www.cnblogs.com/Chen-XiaoJun/p/6217373.html
http://web.jobbole.com/88602/
https://github.com/wengjq/Blog/issues/3