deepcopy 拷貝 深拷貝 淺拷貝 copy shallowcopy

Javascript 的深淺拷貝

曾韻伃 Agnes Tseng 2021/12/29 10:11:36
610

JS世界裡將資料型別分成了兩種型別,分別為基本型別引用型別

•基本型別:string 、number、boolean、null、undefined

 → 存放在棧中的簡單資料段,資料大小確定,記憶體空間大小可以分配,它們是直接按值存放的,所以可以直接按值訪問。

•引用型別:Object(Array、Function...等)

 → 存放在堆記憶體中的物件,變數其實是儲存的在棧記憶體中的一個指標,這個指標指向堆記憶體中的引用地址。



深淺拷貝的區別

淺拷貝

 → 就是傳值,因為直接儲存在棧記憶體中的推記憶體地址,並沒有開闢新的棧,所以複製的兩個物件指向同樣的地址,那當今天修改其中一個物件的屬性,另一個也會跟著改變。

•深拷貝

 → 就是傳址,深拷貝則是會開闢新的棧,兩個物件所對應的地址是不一樣的,修改了一個物件的屬性,另一個則不會被修改到。

 

他們兩個區別就在於儲存的的棧會不會開闢新的,下面舉幾個簡單的例子給各位參考。

 

淺拷貝

•陣列淺拷貝

 → concat()slice()map()filter()...等

 1. concat()

  → 用來組合陣列,但也可以拿空陣列來合併,也是屬於淺拷貝的一種。

const arrayOne = ['Hi','Everyone','!']
const arrayTwo = [].concat(arrayOne)

console.log(arrayOne === arrayTwo) // false
console.log(arrayTwo) // ['Hi','Everyone','!']

 

 2. slice()

  → 用在分割陣列,但參數為0或不傳入,也是屬於淺拷貝的一種。

const arrayOne = ['Hi', 'Everyone', '!']
const arrayTwo = arrayOne
const arrayThree = arrayTwo.slice(0)

console.log(arrayOne === arrayTwo) // true
console.log(arrayTwo) // ['Hi', 'Everyone', '!']

console.log(arrayOne === arrayThree) // false
console.log(arrayThree) // ['Hi', 'Everyone', '!']

 

 3. map()

  → 將執行結果儲存至新陣列,也是屬於淺拷貝的一種。

const arrayOne = ['Hi', 'Everyone', '!']
const arrayTwo = arrayOne.map((item) => item)

console.log(arrayOne === arrayTwo) // false

 

 4. filter()

  → 將條件符合的儲存至新陣列(值為 true),也是屬於淺拷貝的一種。

const arrayOne = ['Hi', 'Everyone', '!']
const arrayTwo = arrayOne.filter((item) => item)

console.log(arrayOne === arrayTwo) // false

 

•物件淺拷貝

 → assign()...等

  1. assign()

   → 用來複製一個或多個物件,也是屬於淺拷貝的一種。

const objOne = {
  a: 1,
  b: 2,
  c: 3,
}

const objTwo = Object.assign({}, objOne)

console.log(objOne === objTwo) // false
console.log(objTwo) // { a: 1, b: 2, c: 3 }

 

深拷貝

•陣列深拷貝

 → JSON.parse()JSON.stringify()

 1. JSON.parse() & JSON.stringify()

const objOne = {
  a: 1,
  b: 2,
  c: 3,
}
const objTwo = JSON.parse(JSON.stringify(objOne))
console.log(objOne === objTwo) // false
console.log(objTwo) // { a: 1, b: 2, c: 3 }

objTwo.a = 4
console.log(objOne) // { a: 1, b: 2, c: 3 }
console.log(objTwo) // { a: 4, b: 2, c: 3 }

  轉換時需注意:

  a. 函式、undefined 、Symbol 會被忽略轉換

  b. NaN 、Infinity 會被轉換成 null

  c. 對於正規表示式型別、函式型別等無法進行深拷貝

 

以上就是對於深淺拷貝的介紹,感謝各位觀看。

 

參考文章:

• JS複習之深淺拷貝
• Javascript 傳值傳址&深淺拷貝
• Javascript的深淺拷貝原來是這樣的 | 七日打卡 

曾韻伃 Agnes Tseng