iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 11
2
自我挑戰組

菜雞們,讓我們一起征服JS及React吧系列 第 11

React菜雞-Day11:學會JS獨特的用法,讓你的React更優雅-第四篇 拷貝還有分深淺

  • 分享至 

  • xImage
  •  
tags: 鐵人賽 React javascript nodejs vscode

鐵人賽第11天,我們延續物件Object主題,來聊聊拷貝這檔事!

什麼!?物件拷貝還有分深淺

/images/emoticon/emoticon77.gif

  • 我們開啟node,輸入以下的指令,來看看會發生什麼事,
let a = {one:100, two:200};     // a object
let b = a;                      // assign a object to b object
b.one = 999;                    // do something in b object

console.log(a); // {one:999, two:200} <== !!?? a object's content is changed !!??

原理是這樣的~位址參考

  • 程式中,宣告的每個變數array,甚至是func,都有自己的位址,就像家裡的門牌號碼一樣,獨一無二。
  • Object的變數,不是存放它的內容,而是存放他的位址,透過間接的方式,存取到同樣的位置。
  • 就像你設定家裡的電話轉接那樣,沒人接時,他會自動轉撥到你的手機上

淺拷貝 vs 深拷貝

  • 所以透過位址參考所完成的拷貝,我們稱之為 淺拷貝
  • 而不管物件有多複雜多深,每個keyvalue都會宣告一個全新的位址去存放,與原本的物件互不影響,我們稱之為 深拷貝

Object.assign提供 "一層" 的深拷貝

/images/emoticon/emoticon13.gif

  • ✍注意: 如果你的Object結構只有一層,Object.assign是一個不錯的拷貝方式。

  • 例子1

let a = {one:100, two:200};     // a object
let b = Object.assign({}, a)    // use Object.assign()
b.one = 999;                    // do something in b object

console.log(a); // {one:100, two:200} 
console.log(b); // {one:999, two:200}  <-- a, b互相不干擾
  • 例子2: 也可以先宣告再使用
let a = {one:100, two:200};     // a object
let cc = {}

Object.assign(cc, a)
  • 為什麼我們說Object.assign()只能用在一層的Object呢?我們用一個結構稍複雜的例子
  • 假設我們宣告一個物件,存放百貨公司各樓層及個銷售區中,各品牌的銷售量。
let saleList = {
  first:{              // 一樓
    A:{                //   |- 銷售A區
       Nike:10,        //   |     |- 販售品牌(Nike)及數量
       Adidas:8},      //   |     |- 販售品牌(Adidas)及數量
    B:{                //   |- 銷售B區
       Jordan:9}},     //.        |- 販售瞟牌(Jordan)及數量
  second:{             // 二樓結構同上
    A:{
       Uniqlo:100, 
       Net:80}}
 }
 
 
let storeA = Object.assign({}, saleList)
storeA.first.A.Nike = 99

console.log(saleList.first.A.Nike); //oops...還是一樣跟著改變

loadash套件提供深拷貝

  • 深拷貝其實只要掌握每一層的每一個key及value都有自己的位址原則,要實現其實不難。
    /images/emoticon/emoticon47.gif
  • 幸運的,有現成的套件可以幫我們完成這件事情~ loadash
  • 安裝方式
npm i -g npm
$ npm i --save lodash
  • 使用方式
const ldsh = require("lodash")

let saleList = {
  first:{              // 一樓
    A:{                //   |- 銷售A區
       Nike:10,        //   |     |- 販售品牌(Nike)及數量
       Adidas:8},      //   |     |- 販售品牌(Adidas)及數量
    B:{                //   |- 銷售B區
       Jordan:9}},     //.        |- 販售瞟牌(Jordan)及數量
  second:{             // 二樓結構同上
    A:{
       Uniqlo:100, 
       Net:80}}
 }

let storeA = ldsh.cloneDeep(saleList); 
storeA.first.A.Nike = 999

console.log(saleList) //<-- 深拷貝,保護原本的資料不被修改
  • 簡單,好用,立馬安裝

結論

  • 鐵人賽第十一天,我們好好認識了物件深拷貝淺拷貝差異,記得剛開始撰寫JS時,莫名其妙掉進這個坑,光debug及搞懂來龍去脈,一天就過了,希望這一篇能讓大家安全避開地雷區!
  • 這幾天我們探討JS獨特的用法,對於我們未來在開發React有不錯的幫助,建議各位可以多練習,熟悉內化後,就能行雲流水般的撰寫啦!
    /images/emoticon/emoticon62.gif

上一篇
React菜雞-Day10:學會JS獨特的用法,讓你的React更優雅-第三篇 解構賦值
下一篇
React菜雞-Day12:React Hook第二招 ~ Context 開啟資源共享的時代
系列文
菜雞們,讓我們一起征服JS及React吧30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言