淺拷貝與深拷貝
淺拷貝和深拷貝的對比,主要體現(xiàn)在引用數(shù)據(jù)類型的拷貝上,對于淺拷貝來說,B拷貝了A,A改變,B會受影響也發(fā)生改變,主要原因是,A和B在淺拷貝時只復制了指向對象的指針,A、B的指針指向堆內存的同一塊區(qū)域。對于深拷貝來說,是復制并創(chuàng)建一個一模一樣的對象,也就是在內存中重新開辟一塊區(qū)域,所以B拷貝了A,A發(fā)生改變時,B不受影響。
淺拷貝的實現(xiàn):
function cloneShallow(source){
var target = {};
for(var key in source){
//判斷一個屬性是在對象本身而不是繼承自原型鏈,判斷key屬性是否是在對象本身
if(Object.prototype.hasOwnProperty.call(source,key)){
target[key] = source[key];
}
}
return target;
}
深拷貝
實現(xiàn)思路,淺拷貝第一層,判斷如果為對象則進行遞歸淺拷貝。
function cloneDeep1(source){
var target = {};
for(var key in source){
if(Object.prototype.hasOwnProperty.call(source,key)){
if(typeof source[key] == 'object') {
target[key] = cloneDeep1(source[key]);
}else{
target[key] = source[key]
}
}
}
return target
}
上面這種方法,沒有考慮值為null的情況,當值為null時會克隆為{}。做出修改,
思路為:進行傳入參數(shù)進行判斷,當傳入null時返回null,優(yōu)化對象的判斷邏輯。同時考慮數(shù)組的兼容
//判斷是否為對象
function isObject(obj){
return typeof obj === 'object' && obj != null;
}
//克隆,添加數(shù)組的判斷
function deepClone2(source){
if(!isObject(source)) return source;//非對象返回自身
var target = Array.isArray(source) ? [] : {};//數(shù)組判斷
for(var key in source){
if(Object.prototype.hasOwnProperty.call(source,key)){
if(isObject(source[key])){
target[key] = deepClone2(source[key]);
}else{
target[key] = source[key]
}
}
}
return target;
}
循環(huán)引用,深拷貝的實現(xiàn)
循環(huán)引用:簡單說就是a對象的屬性為a本身
解決方案:使用一個哈希表存儲已經拷貝過的對象,當檢測到當前對象已存在于哈希表中時,取出該值并返回。
//深拷貝解決循環(huán)依賴問題采用es6的WeakMap
function deepClone3(source, hash = new WeakMap()){
if(!isObject(source)) return source;
if(hash.has(source)) return hash.get(source)//新增代碼查哈希表
var target = Array.isArray(source)? [] : {};
hash.set(source, target);
for(var key in source){
if(Object.prototype.hasOwnProperty.call(source, key)){
if(isObject(source[key])){
target[key] = deepClone3(source[key],hash);//新增代碼,傳入哈希表
}else{
target[key] = source[key]
}
}
}
return target
}
測試用例:
var a = {
name:"yuanyuan",
book:{
title:"you like js",
price:'45'
},
a1: undefined,
a2: null,
a3: 123
}
var b = cloneShallow(a);
var c = cloneDeep1(a);
var d = deepClone2(a);
a.circleRef = a;
var f = deepClone3(a);
var e = deepClone4(a);
a.name = "高級前端進階";//基本數(shù)據(jù)類型參數(shù)不變
a.book.price = "65";//引用數(shù)據(jù)類型拷貝,淺拷貝時受影響,深拷貝時不受影響
//淺拷貝 a變了,b沒變
console.log(b)
console.log(c)
console.log(d)
console.log(f);
console.log(e);
測試結果

image.png
參考:https://segmentfault.com/a/1190000019462847
文中解決循環(huán)引用使用數(shù)組的方法,試了之后發(fā)現(xiàn)A的改變會影響B(tài)
測試結果如下:

image.png