Object 的存储形式

JavaScript 中Object以引用类型的形式保存在堆内存中,不许与直接访问与修改,在操作时也只是操作对象的引用。

将一个对象赋值给另一个对象。

1
2
3
4
var a = [1, 2, 3];
var b = a;
b.push(4);
console.log(a); // [1, 2, 3, 4]

这就是由于对象类型直接赋值,只是将引用指向同一个地址,导致修改了obj1会导致obj2也被修改。

Object.assign( )

ES6为我们提供了一种十分好用的方法,Object.assign(target, …source)方法

assign( ) 方法接受多个参数,第一个参数 target 为拷贝目标,剩余参数 …source 是拷贝源。此方法可以将 …source 中的属性复制到 target 中,同名属性会进行覆盖,并且在复制过程中实现了’伪’深拷贝。

在 Redux 的 reducer 中我们也用到了 Object: ...object,newValue: value 的形式来确保 reducer 本身是个纯函数的条件。

… :扩展操作符(spread operator)并不是 ES6 语法的一部分,甚至都不是 ES Next 语法的一部分,但是因为其语法简单,已经被广泛使用,因为 babel 的存在,也不会有兼容性问题,所以我们可以完全放心使用。

​ ——《深入浅出 React 和 Redux》

深拷贝与浅拷贝

深拷贝和浅拷贝只针对像 Object, Array 这样的复杂对象的。简单来说,浅拷贝只拷贝一层对象的属性,而深拷贝则递归拷贝了所有层级。

下面是一个简单的浅拷贝实现:

1
2
3
4
5
6
7
8
9
10
11
12
var obj = { a:1, arr: [2,3] };
var copyObj = Copy(obj);

function Copy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}

因为浅复制只会将对象的各个属性进行依次复制,并不会进行递归复制,而 JavaScript 存储对象都是存地址的,所以浅拷贝会导致 obj.arrcopyObj.arr 指向同一块内存地址,所以导致的结果就是:

1
2
copyObj.arr[1] = 5;
console.log(obj.arr[1]); // 5

而深拷贝则不同,它不仅将原对象的各个属性逐个复制出去,而且将原对象各个属性所包含的对象也依次采用深复制的方法递归复制到新对象上。这就不会存在上面 obj 和 copyObj 的 arr 属性指向同一个对象的问题。

1
2
3
4
5
6
7
8
9
10
11
12
13
function inCopy(obj1,obj2) {
var obj1 = obj1 || {}; //容错处理
for (var k in obj2) {
if(obj2.hasOwnProperty(k)){ //只拷贝实例属性,不进行原型的拷贝
if(typeof obj2[k] == 'object') { //引用类型的数据单独处理
obj1[k] = Array.isArray(obj2[k])?[]:{};
inCopy(obj1[k],obj2[k]); //递归处理引用类型数据
}else{
obj1[k] = obj2[k]; //值类型的数据直接进行拷贝
}
}
}
}

需要注意的是,如果对象比较大,层级也比较多,深复制会带来性能上的问题。在遇到需要采用深复制的场景时,可以考虑有没有其他替代的方案。在实际的应用场景中,也是浅复制更为常用。

引用:javascript中的深拷贝和浅拷贝?

最后更新: 2018年09月09日 17:13

× 感谢支持
打赏二维码