JavaScript 的 深拷貝和淺拷貝


深拷貝和淺拷貝都是針對的引用類型,

JS中的變量類型分為值類型(基本類型)和引用類型;

對值類型進行復制操作會對值進行一份拷貝,而對引用類型賦值,則會對地址進行拷貝,最終兩個變量指向同一份數據

 

一、先來看看JS中的數據類型

let x = 1;        //number類型
let x = 0.1;     //number類型,JS不區分整數值和浮點數值

let x = "hello world"; //由雙引號內文本構成字符串
let x = 'javascript';   //單引號內文本同樣可以構成字符串

let x = true;    // boolean 布爾類型

let x = null;
let x = undefined;  //null和undefined很相似,是特殊的類型

JS 中數據分為兩種類型:

  • 原始數據類型
    • number 
    • string
    • boolean
    • null
    • undefined
  • 對象數據類型
    • array 數組 特殊對象類型 
    • function 函數 特殊對象類型
    • object 對象

還有 undefined 和 null,此處暫不討論

object對象需要注意的點:

  • 對象是可變的,即值是可以修改的
  • 對象的比較並非值得比較

比如:var a = [], b = [];

     a == b;   //false,只有在引用相同(指向的地址相同)時,兩個只才會相等

由此可以延伸出 深拷貝和淺拷貝 的問題。

=========================================================================

我們的困惑:

1. 看着相等,卻又不等

 

 

 2. 想要不等,卻又相等

 

 

 那么造成這樣問題的原因在哪呢?

> 對象的引用 

> 引用只會對地址進行賦值, 所以

1. 不同的變量 a 和 b,他們的地址不同,即使數據相同,本身也不會相等,這是造成困惑一的原因;

2. 而變量 aa 和 bb 指向同一地址,當該地址的數據改變時,所有使用該地址的變量全部改變(同一數據),這是造成困惑二的原因

 

達不到我們想要的效果,怎么辦呢?

二、引用(對象)數據類型的賦值和比較問題

解決辦法: 笨辦法,也是唯一的方式,既然對象數據類型 是由基本數據類型組成的,而基本數據類型可以正常賦值、比較,那我們就把對象類型變成一個個的基本類型進行操作

 

方法一: 遍歷對象中的內容,一個一個的進行賦值,這樣只進行一層拷貝的方式了,就是淺拷貝

// 淺拷貝方法
function shallowClone(source) {
    let target = {};
    for(leti in source) {
        if (source.hasOwnProperty(i)) {
            target[i] = source[i];
        }
    }
    return target;
}

 

方法二: 相對於一層拷貝的淺拷貝,無線層次的拷貝叫做 深拷貝

// 簡單深拷貝
function clone(source) {
    let target = {};
    for(let i in source) {
        if (source.hasOwnProperty(i)) {
            if (typeof source[i] === 'object') {
                target[i] = clone(source[i]); // 判斷仍是對象,就進行遞歸
            } else {
                target[i] = source[i];
            }
        }
    }
    return target;
}

上面 clone 方法 和 shallowClone 方法的 區別就是 多了 遞歸

但是仍然有些問題需要注意:

  • 參數需要檢驗
  • 判斷是否對象的邏輯不夠嚴謹
  • 需要考慮數組的情況

暫不細說,判斷對象可以用此方法:

// 更嚴謹的判斷對象的方法
function isObject(x) {
    return Object.prototype.toString.call(x) === '[object Object]';
}

 

當然我們也可以參考其他方法或使用插件

比如: 簡單粗暴的 JSON.parse(JSON.stringify(oldObj))

比如: ES6的assign方法(淺拷貝)

比如: 通過immutableJS實現深拷貝

 

三、最后

無論 淺拷貝,還是深拷貝 都會帶來性能問題(平白的需要遍歷,只是重新賦值)

所以我們對象最好寫的淺一點,精簡一點。。。

 

詳細可以看這篇: https://yanhaijing.com/javascript/2018/10/10/clone-deep/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM