因为公司前端资料已经处理成单层结构,所以都没注意到浅拷贝、深拷贝的实际差别。
在读完高手文章後,才发现和自己想的不一样。
也顺手将文章重点整理,分享给大家,别枉费自己写这麽多Code。
string
、number
、boolean
、null
、undefined
Object.assign()
...
array.slice()
array.concat()
array.map()
array.filter()
forEach
+push()
...
JSON.parse(JSON.stringify())
_.cloneDeep()
...等等var a = 10;
var b = 10;
console.log(a === b); // true
a
、b
皆为基本型别,故互相比较时回传true
var obj1 = { a : 1 };
var obj2 = { a : 1 };
console.log(obj1 === obj2); // false
虽然物件内容相等,但是物件的记忆体位置却不同,故比较结果为false
。
不同的例子
var obj1 = { a : 1 };
var obj2 = obj1;
obj1.a = 0;
console.log(obj1.a); // 0
console.log(obj2.a); // 0
obj2.a = 2;
console.log(obj1.a); // 2
console.log(obj2.a); // 2
console.log(obj1 === obj2); // true
当我们修改任何一边的属性时,会一起变动,这是因为物件透过传址的方式指派,所以两个物件会指向同一个记忆体位置,实际上也意味着并未产生新的物件。
但若是这样呢?
var obj1 = { a : 1 };
var obj2 = obj1;
obj1.a = 0;
console.log(obj1.a); // 0
console.log(obj2.a); // 0
obj2.a = 2;
console.log(obj1.a); // 2
console.log(obj2.a); // 2
obj1 = {}; // 指派新的物件
console.log(obj1 === obj2); // false
当obj1
被指向新的记忆体位置,但是obj2
依然保持原本的记忆体位置,因此这时obj1
、obj2
彼此就毫无关系了。
复制物件可以分为两种
物件的浅拷贝
Object.assign()
...
Object.assign(target, source)
能复制一个或多个物件自身所有可数的属性到另一个目标物件。
将原本的obj
内容复制到另一个空物件
var obj = { a : 1, b : 2 };
var obj2 = Object.assign({}, obj);
console.log(obj2); // { a : 1, b : 2 }
console.log(obj == obj2); // false
展开运算子
var obj = { a : 1, b : 2 };
var obj2 = { ...obj1 };
console.log(obj2); // { a : 1, b : 2 }
console.log(obj === obj2); // false
阵列的浅拷贝
array.slice()
array.concat()
array.map()
array.filter()
forEach
+push()
...
slice()
原本是用在分割阵列,但用参数为0或不传入的话,相当於浅拷贝
var arr = [1, 2, 3, 4];
var arr2 = arr;
console.log(arr === arr2); // true
var arr3 = arr.slice(0);
console.log(arr === arr3); // false
console.log(arr3); // [1, 2, 3, 4]
concat()
原本是用在组合阵列,但可以使用空阵列合并,也相当於浅拷贝
var arr = [1, 2, 3, 4];
var arr2 = [].concat(arr);
console.log(arr === arr2); // false
consoloe.log(arr2); // [1, 2, 3, 4]
map()
是将执行结果会存至新阵列,若回传原本的元素,也相於浅拷贝
var arr = [1, 2, 3, 4];
var arr2 = arr.map(x => x);
console.log(arr === arr2); // false
console.log(arr2); // [1, 2, 3, 4]
filter
是将符合条件的值存至新阵列,若条件皆为true
,也相当於浅拷贝
var arr = [1, 2, 3, 4];
var arr2 = arr.filter(x => { return true; } );
console.log(arr === arr2); // false
console.log(arr2); // [1, 2, 3, 4]
...
也可用於阵列,效果也是浅拷贝
var arr = [1, 2, 3, 4];
var arr2 = [ ...arr ];
console.log(arr === arr2); // false
console.log(arr2); // [1, 2, 3, 4]
至於为什麽叫浅拷贝,可以看以下程序码
var obj1 = {
foo : 10,
bar : {
baz : 20,
},
};
var obj2 = { ...obj1 };
console.log(obj1 === obj2); // false
console.log(obj1.bar === obj2.bar); // true
浅拷贝後,obj1
、obj2
已经是两个不同的物件,但是第二层的物件却是相同的记忆体位置。
再看看阵列
var arr = [{a : 1}, {b : 2}];
var arr2 = [...arr];
console.log(arr === arr2); // false
console.log(arr[0] === arr2[0]); // true
浅拷贝後,arr
、arr2
已经是不同的阵列,但是里面的物件却是同一个。
上述只是有容器不同,若有巢状或多维的状况,仍然是传址。因为深层的物件或阵列还是传址,不会完全复制一份,所以称为『浅拷贝』。
深拷贝是完全复制一份新的,不会共用记忆体位置。
Json.parse(Json.stringify())
_.cloneDeep()
...等等利用JSON
var obj1 = {
a : 1,
b : {
val: 5
}
};
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj1 === obj2); // false
console.log(obj1.b === obj2.b); // false
但JSON的转法须注意
undefined
、Symbol
会被忽略转换NaN
、Infinity
会被转换成 null
var obj1 = {
a: function() {},
b: undefined,
c: Symbol(''),
d: NaN,
e: Infinity,
f: -Infinity,
};
var obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj2); // {d: null, e: null, f: null}
<<: 缓冲区溢出和记忆体泄漏(Buffer Overflow and Memory Leak)
>>: Python 演算法 Day 1 - 程序基础 & 简介
前言 这篇适合给first time leader,特别是刚被promote成team leade...
Day 18 - Android Studio 如何切换Activity(分页) 昨天我们讲了如何使...
本篇文章同步发表在 HKT 线上教室 部落格,线上影音教学课程已上架至 Udemy 和 Youtu...
接续前面的内容,还有几个东西没有研究到... 3. mutations 前面是学到的向仓库取资料的办...
今天是铁人赛的最後一天了(虽然我已经完赛了),这部影片也会是这系列的最後一部了,真的要结束了(´༎ຶ...