JS中的深淺拷貝以及實現深拷貝的幾種方法.

lukerSpringTree發表於2018-09-11

什麼是淺拷貝?從基本型別和棧記憶體以及堆記憶體講起.

我們在js中最常用的賦值方式就是淺拷貝.如: 兩個物件a,b. 那麼 讓b等於a.

var b = a;

這就是最基本的淺拷貝了.那淺拷貝的表現形式是什麼呢? 解決這個問題我們要先談談js中的資料型別了.
在es5中有6中資料型別它們是:undefined,null,Boolean,Stirng,Number,Object.
在es6中新增一個原始的資料型別Symbol那麼js就有了7個資料型別了.
但是這些資料型別又可以分為基本資料型別和引用資料型別.

  1. 基本資料型別(undefined,null,Boolean,Stirng,Number):
    如何理解呢?它們保持的變數名(如:a)都標示在棧記憶體中的實際的值.如 var a = 1; 那麼就是說a標示棧記憶體中的某一值為1的物件.

  2. 引用資料型別(Object):
    引用資料型別與基本資料型別不同點就是在"引用"這兩個字上面.它本質上表示在棧記憶體上的一條指標記錄.而指標所指的方向(指到堆記憶體裡面),就是那塊堆記憶體的物件,這才是引用型別真正的值.引用型別棧記憶體的表現其實就是一條指標記錄.

那麼究竟什麼是淺拷貝呢?

淺拷貝就是棧記憶體的拷貝. 比如: 我把 a 物件的值賦給 b物件 就是把我a在棧記憶體裡面的內容複製給b了.

var a = b

如果a是基本資料型別.那麼b在棧記憶體裡面獲得的就是一個和a一樣內容的東西(拷貝).他的內容是一個基本型別.

如果a是引用資料型別.那麼b在棧記憶體裡面獲得的就是一個和a一樣內容的東西(拷貝).它的內容是一個指標(指向同一塊對記憶體).!!!(淺拷貝的本質!) 既然b獲得是一條與a相同的指標記錄.那麼a和b本質上都連向同一塊堆記憶體了! 這就是淺拷貝

所以當我們改變b物件中某個屬性的值,a中的屬性值也隨之變化. 因為他們擁有相同的指標.

綜上淺拷貝就是說兩個物件拷貝的是棧記憶體中的內容; 基本型別就獲得的是對應的值,而引用型別獲得的就是指標!!!

指標是導致淺拷貝的表現的根本原因.

什麼是淺拷貝的表現. 就是 b 變化了 a也隨之變化. 且永遠 a===b

程式碼如下:

let a = {name: 'ldj',age: 30}
let b = a
b.age = 40
console.log(b)
console.log(a)

console.log(a === b)

什麼是深拷貝?

通過上面的描述我們知道所謂淺拷貝就是棧記憶體裡面的內容拷貝.而Object型別的話拷貝的就是指標記錄(指向同一塊對記憶體). 那深拷貝呢. 就是重新建一塊堆記憶體了,b物件的指標指向這塊新的堆記憶體.a和b指向了不同的堆記憶體(堆記憶體裡面的屬性的值如果是Object型別的話也指向新的堆記憶體).

深拷貝的方法:

  1. JSON.parse(JSON.stringify(obj)) 方法

let b = JSON.parse(JSON.stringify(a))

其實上面這一輪操作就是讓b的指標從新獲得一塊堆記憶體了.

  1. 遞迴遞迴去複製所有層級屬性
function deepClone(obj) {
  if (obj == null) return null;
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  if (typeof obj !== 'object') return obj;
  let t = new obj.constructor
  for (let key in obj) {
    t[key] = deepClone(obj[key])
  }
  return t;
}
複製程式碼

使用遞迴,每一個層級的去查.如果是引用型別.那就new一個新的物件(new 出來的東西肯定得有一塊新的對記憶體來儲存吧.) 然後再把整個新物件return出去.

[誤區]還有其他深拷貝的方法了嗎?

可能很多朋友認為.

let b = Object.assign({}, a)

或者

let b = {...a, ...{}}

如果a是 Array 型別的值

let b = [].concat(a)

或者

let b = [...a, ...[]]

以上幾種方法其實指實現了第一層級的 '深'拷貝. 而沒有實現真正意義上的深! 可以這樣理解.它只調了deepCloneErr()方法一次 沒有去做遞迴!

第一次寫文章,文字差,沒配圖,請多包涵.

有錯誤請指正,
有疑問可共同探討.
謝謝.

相關文章