今天看es6的时候忽然想到一个问题就是针对于js的深拷贝和浅拷贝的问题,其实说直接点那,就是深复制和浅复制只针对像 Object, Array 这样的复杂对象的。简单来说,浅复制只复制一层对象的属性,而深复制则递归复制了所有层级。
因为浅复制只会将对象的各个属性进行依次复制,并不会进行递归复制,而 JavaScript 存储对象都是存地址的,所以浅复制会导致 obj.arr 和 shadowObj.arr 指向同一块内存地址,大概的示意图如下。
举一个列子哈:
let obj = { a:11, b: [22,33] }; function objCopy(src) { let dst = {}; for (let prop in src) { if (src.hasOwnProperty(prop)) { dst[prop] = src[prop]; } } return dst; } let _copy = objCopy(obj);
因为浅复制只会将对象的各个属性进行依次复制,并不会进行递归复制,而 JavaScript 存储对象都是存地址的,所以浅复制会导致 obj.b和_copy.b 指向同一块内存地址,大概的示意图如下。
导致的结果就是这样:
_copy.arr[1] = 88; obj.b[1] // = 88而深复制则不同,它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。这就不会存在上面 obj 和 _copy的 b属性指向同一个对象的问题。
深拷贝要实现的效果是这样的:
实现深拷贝的方法如下
最简单的深拷贝,拿好:
b = JSON.parse( JSON.stringify(a) )
不过这有局限性:
- 无法复制函数
- 原型链没了,对象就是object,所属的类没了。
但是简单,大多时候完全可以满足需求了
jQuery.extend第一个参数可以是布尔值,用来设置是否深度拷贝的:jQuery.extend(true, { a : { a : "a" } }, { a : { b : "b" } } ); jQuery.extend( { a : { a : "a" } }, { a : { b : "b" } } );
(数组深拷贝)
var arr = ["One","Two","Three"]; var arrtoo = arr.slice(0); arrtoo[1] = "middle"; document.writeln("数组的原始值:" + arr + "<br />");//Export:数组的原始值:One,Two,Three document.writeln("数组的新值:" + arrtoo + "<br />");//Export:数组的新值:One,middle,Three
concat() 方法用于连接两个或多个数组。 该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。 语法 arrayObject.concat(arrayX,arrayX,......,arrayX) 说明 返回一个新的数组。该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的。如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组。
(对象深拷贝)
就是把对象的属性遍历一遍,赋给一个新的对象。
var deepCopy= function(source) { var result={};
for (var key in source) {
result[key] = typeof source[key]===’object’? deepCoyp(source[key]): source[key];
}
return result;
}
var cloneObj = function(obj){
var str, newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){
return;
} else if(window.JSON){
str = JSON.stringify(obj), //系列化对象
newobj = JSON.parse(str); //还原
} else {
for(var i in obj){
newobj[i] = typeof obj[i] === 'object' ?
cloneObj(obj[i]) : obj[i];
}
}
return newobj;
};
这个函数可以深拷贝 对象和数组
小弟水平有限,大神勿喷,理解不对的地方请批评指正。谢谢~~