js淺拷貝與深拷貝,及深拷貝的幾種實現(xiàn)方式

淺拷貝與深拷貝

淺拷貝和深拷貝的對比,主要體現(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

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容