(JavaScript)傳值 Pass by value、傳址 Pass by reference以及Pass by sharing

from https://dev.to/albertomontalesi/learn-pass-by-value-and-pass-by-reference-in-javascript-18ch

本篇同步發佈在Medium平台上 Medium連結

這篇希望能透過一些簡單的範例,讓讀者們能夠輕易了解JavaScript的語言特性。

Data Type

在JavaScript裡,有多種的資料型別(Data Type),但主要分為兩大類,一類是原始型別(Primitive Type),另一類是物件型別(Object Type)。

原始型別 Primitive Type

  • String

  • BigInt

  • Number

  • Boolean

  • Null

  • Undefined

  • Symbol( 在 ECMAScript 6 定義)

物件型別 Object Type

  • Primitive type以外的,例如object, array, function …等

一般來說,Primitive Type會是pass by value,而Object Type則會是pass by reference,以下會用幾個簡單例子來示範。

1. 原始型別 Pass by value

變數、記憶體位址、值

首先,要先來了解在電腦的底層世界,想像記憶體空間就像是一個一個的空間,每一個空間都有他的位址,並可以在該空間內儲存值。為了方便取用,才有了「變數」的存在,拿來連結(指向)這些記憶體位址,宣告變數賦值,就是向電腦要一個記憶體空間來儲存值。

var a = ‘jerry’; ,其實是變數 a 指向電腦中某記憶體的位置(ex: 0x01) ,在這個記憶體位置中,儲存 jerry這個值。

如果我再宣告了一個 var b = a; ,雖然 b 和 a 的值一樣都是 ‘jerry’ ,但其實變數 b 是指向了另一個不一樣的記憶體位置 (ex:0x02),把 a 的值 copy 過來存,a 和 b 是存在於兩個獨立不同的記憶體位置中:

在第7行b = ‘tony’;,則是將記憶體位址0x02儲存的值賦予為tony,如下圖 :

2. 物件型別 Pass by reference

var arr1 = [1,2,3]; ,表示 arr1 指向一個新的記憶體位置(ex: 0x01),如果再建立第二個陣列並且讓他等於 arr1: var arr2 = arr1; ,這時 arr2 則會直接指向 arr1 的記憶體位置(0x01),所以不論 arr1 儲存的值為多少, arr2 都會得到一樣的值:

在第3行arr2[0] = 666;,則是將記憶體位址0x01儲存的值index 0 賦予為666,如下圖 :

3. Pass by sharing

pass by sharing 的定義就有點像融合了pass by value 和 pass by reference:

  • 碰到原始型別,表現行為是 pass by value。

  • 碰到物件型別,如果只是改變內容,表現行為是 pass by reference,但是如果對物件作重新賦值,表現行為是 pass by value。

所以才會出現這一派的論點,覺得 Javascript 其實是 pass by sharing。

以下的流程分解圖可以更清楚了解物件指向的記憶體位置!

第1~4行

第5行

第6行,改變內容(pass by reference)

第7~10行,重新賦值(pass by value)

第11行

由以上範例可得知,book 在第6行被改變內容(pass by reference),在第7~10行被重新賦值(pass by value),因此bookObj1、bookObj2最終才會有此差異。

結論:在不管名詞定義為何(有些人認為只有pass by sharing),先以行為來分類的話,primitive type基本上是pass by value,而object基本上是 pass by reference,唯一要注意的是重新賦值這個動作造成reference改變所造成的影響

下一篇將會來討論:淺拷貝Shallow Copy & 深拷貝Deep Copy,並且使用Lodash來處理資料

comments powered by Disqus