--- tags: JavaScript, hexo部落格, 六角筆記王 title: 傳值與傳址 --- ## 情況 某天,自己需要更改陣列資料時,遇到一個莫名其妙的情況。 修正前 : ```javascript // 原始資料陣列 let data = [ { name: 'A' }, { name: 'B' } ]; // 暫存資料 let temp = { name: 'C' }; data.forEach(item => { if (item.name === 'B'){ item = temp } }) console.log(data[1]) // { name: 'B'} ``` `變數 data` 內的資料,居然還是原封不動! 修正後 : ```javascript data.forEach(item => { if (item.name === 'B'){ item.name = temp.name } }) console.log(data[1]) // { name: 'C'} ``` `變數 data` 內的資料終於修改成功了! 不過,為什麼會這樣? --- ## 傳值 當我們宣告一個新的變數時,其預設值會是 `undefined` , 若我們賦予這個變數一個值,後續取用這個變數時,就會是其值, 像是這樣 : ```javascript let a = 1 console.log(a) // 1 ``` 若我們再宣告一個`變數 b`並賦予其值為`變數 a`,`變數 b` 的值會是? ```javascript let b = a console.log(b) // ? ``` 此時狀態會是"傳遞值",也就是說`變數 b`的值會是 1, 若我們再將`變數 a`重新賦予值為 100,`變數 b` 也不會被改變其值。 > 在 JavaScript 裡,布林值、字串、數值、null、undefined 都是 Pass by value。 ```javascript // 完整範例 let a = 1 let b = a a = 100 console.log(b) // 1 ``` --- ## 傳址 / 傳參考 上面的情況都是純值,換成物件、陣列或是函式呢? 假設我們程式碼如下 : `變數 b` 會是? ```javascript let a = { name: 'A' } let b = a a = 1 console.log(b.name) // ? ``` `變數 b` 不會受到變動,因為它是傳值,因此 `b.name` 為 `'A'`。 若變更物件的屬性值呢? ```javascript let a = { name: 'A' } let b = a a.name = 'B' console.log(b.name) // 'B' ``` 變更物件屬性值時,`變數 b`連帶的也受到影響,也就是傳參考。 > 在 JavaScript 裡,物件、陣列、函式都是 Pass by reference。 那我們知道有這樣情況後,使用函式來看看會怎樣? ```javascript // 宣告一樣的變數作為範例 let d = { name: 'D' } let e = { name: 'E' } const fn = data => { data = e } fn(d) console.log(d) // ? ``` 在上述的範例中,`變數 d`維持不變,因為它是傳值, 若改成 `data.name = e.name`,此時才會是傳參考。 ## 回歸情況 回到一開始的程式碼,很單純地想讓資料變更,於是重新賦予其值, 但事實沒這麼簡單,由於 JavaScript 擁有兩種特性,傳值與傳參考,特別是物件, 單純的物件複製是傳值,修改物件屬性值則為傳參考, 於是產生了 Pass by sharing 來稱呼這種情況。 ## 參考來源 > 1. [SimonAllen - Day17 傳值 by value 與傳址 by reference](https://ithelp.ithome.com.tw/articles/10192342) > 2. [Kuro Hsu - 重新認識 JavaScript: Day 05 JavaScript 是「傳值」或「傳址」?](https://ithelp.ithome.com.tw/articles/10191057) > 3. [OneJar - 你不可不知的 JavaScript 二三事#Day26:程式界的哈姆雷特 —— Pass by value, or Pass by reference?](https://ithelp.ithome.com.tw/articles/10209104)