情況
某天,自己需要更改陣列資料時,遇到一個莫名其妙的情況。
修正前 :
1 | // 原始資料陣列 |
變數 data
內的資料,居然還是原封不動!
修正後 :
1 | data.forEach(item => { |
變數 data
內的資料終於修改成功了!
不過,為什麼會這樣?
傳值
當我們宣告一個新的變數時,其預設值會是 undefined
,
若我們賦予這個變數一個值,後續取用這個變數時,就會是其值,
像是這樣 :
1 | let a = 1 |
若我們再宣告一個變數 b
並賦予其值為變數 a
,變數 b
的值會是?
1 | let b = a |
此時狀態會是”傳遞值”,也就是說變數 b
的值會是 1,
若我們再將變數 a
重新賦予值為 100,變數 b
也不會被改變其值。
在 JavaScript 裡,布林值、字串、數值、null、undefined 都是 Pass by value。
1 | // 完整範例 |
傳址 / 傳參考
上面的情況都是純值,換成物件、陣列或是函式呢?
假設我們程式碼如下 : 變數 b
會是?
1 | let a = { |
變數 b
不會受到變動,因為它還是傳值,因此為 'A'
。
若變更物件的屬性值呢?
1 | let a = { |
變更物件屬性值時,變數 b
連帶的也受到影響,也就是傳參考。
在 JavaScript 裡,物件、陣列、函式都是 Pass by reference。
那我們知道有這樣情況後,使用函式來看看會怎樣?
1 | // 宣告一樣的變數作為範例 |
在上述的範例中,變數 d
維持不變,因為它是傳值,
若改成 data.name = e.name
,此時才會是傳參考。
回歸情況
回到一開始的程式碼,很單純地想讓資料變更,於是重新賦予其值,
但事實沒這麼簡單,由於 JavaScript 擁有兩種特性,傳值與傳參考,特別是物件,
單純的物件複製是傳值,修改物件屬性值則為傳參考,
於是產生了 Pass by sharing 來稱呼這種情況。