參數的傳遞分為按值傳遞和按引用傳遞,而 JavaScript 中參數的傳遞只有按值傳遞。
ECMAScript 中所有函數的參數都是以值傳遞的。所謂按值傳遞就是:
把函數外部的值複製給函數內部的參數,就和把值從一個變數複製到另一個變數一樣。 -- 《JavaScript 進階程式設計》我們知道 JS 中,既有基本資料型別又有引用資料型,那麼二者的值傳遞有什麼樣的差異呢?
先給結論
在傳遞基本資料型別時,被傳遞的值會被複製給一個局部變數(arguments 類別陣列物件中的一個元素)。在傳遞參考資料型別時,會把這個值的記憶體位址賦給一個局部變數。在 JS 中,資料型別分為基本型別和參考型別。
其中基本型別包括:number, string, boolean, undefined, null, Symbol(es 6 新增)。基本型別的值是保存在堆疊記憶體當中的。
基本資料型別的值本身是不會改變的。
let num1 = 5; let num2 = num1;
將保存著原始值的變數num1 賦值給num2 後,會將原始值num1 的副本賦值給新變數num2, 此後這兩個變數是完全獨立的,他們只是擁有相同的數值而已,是完全獨立的拷貝,互不干涉。
引用資料型別包括:Function, Array, Object 等等除了基本資料型別之外的資料。引用資料型別是保存在堆內存當中的。
JS 不允許直接操作物件的記憶體空間,所以引用資料型別是透過儲存在變數處的值,也就是一個指標(point),指向儲存物件的記憶體位址,從而進行存取的。
let obj1 = new Object(); var obj2 = obj1;
當把引用型別的變數 obj1 賦給另一個變數 obj2 後,obj2 接受的其實是引用型別資料的記憶體位址指標。所以,判斷兩個引用型別是否相等,其實比較的是記憶體位址是否相等。
var num = 1; function foo(param) { param = 2; } foo(num); console.log(num); // num 值仍为1, 并没有受 param = 2 赋值影响
以上程式碼:
當按值傳遞每次傳遞參數時,都會拷貝一份副本到函數內部,拷貝前後的兩個值互不影響。
var obj = { num: 1 }; function foo(o) { o.num = 2; console.log(obj.num); // 2 } foo(obj); console.log(obj.num); // 2
以上程式碼,foo 函數把obj 物件當作實參,執行完畢後把obj 物件的num 屬性給改變了,說明參數o 物件和外部變數obj 物件是同一個物件。說好的按值傳遞呢,怎麼還是把原來的物件給改變了呢。
再看下面這段程式碼:
var obj = { num: 1 }; function foo(o) { o = 100; } foo(obj); console.log(obj.num); // 1
如果是按引用傳遞的話,按理來說obj 物件會被改變會100 才對。
準確的說,JS中的基本類型按值傳遞,物件類型按共享傳遞的(call by sharing,也叫按物件傳遞、按物件共享傳遞)
在共享傳遞中對函數形參的賦值,不會影響實參本身的值。所以,形參所引用的物件是同一個,由於物件是可變的(mutable),修改形參中物件的屬性值,會影響到原本物件的屬性值。
依引用傳遞是傳遞物件的引用,而依共用傳遞是傳遞物件的拷貝的副本,所以副本本身無法直接修改。而拷貝副本也是一種拷貝,所以也被認為是按值傳遞。
基本型別本身是按值傳遞,具有不可變性(immutable),對基本型別的修改,實質上都是在堆疊記憶體中創造了新的值。
複習鞏固:
var obj = { num : 0 }; obj.num = 100; var o = obj; o.num = 1; obj.num; // 1, 被修改 o = true; obj.num; // 1, o 是对象的一个拷贝,对 o 本身的修改,不会改变 obj 对象本身的值。
JavaScript 中參數的傳遞只有按值傳遞
,而對於參考類型的傳遞,是一種共享傳遞,傳遞的是資料類型的拷貝副本,雖然引用的是同一個對象,但是無法透過改變形參來改變實參本身。
JS 中把這種拷貝也認為是用值傳遞。
#以上是JavaScript中按值傳遞的詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!