最近在研究 lambda
演算中的 η-變換
在 JavaScript 中的應用,偶然在 stackoverflow 上看到一個比較有意思的問題。關於 JavaScript 的求值策略,問JS中函數的參數傳遞是按值傳遞仍是按引用傳遞?回答很經典。javascript
function changeStuff(a, b, c) { a = a * 10; b.item = "changed"; c = {item: "changed"}; } var num = 10; var obj1 = {item: "unchanged"}; var obj2 = {item: "unchanged"}; changeStuff(num, obj1, obj2); console.log(num); // 10 console.log(obj1.item); // changed console.log(obj2.item); // unchanged
changeStuff
內部改變b.item
的值將不會影響外部的obj1
對象的值。changeStuff
內部所作的改變將會影響到函數外部全部的變量定義,num
將會變成100、obj2.item
將會變成changed
。很顯然實際不是這樣子的。因此不能說JS中函數的參數傳遞嚴格按值傳遞或按引入傳遞。總的來講函數的參數都是按值傳遞的。JS中還採用一種參數傳遞策略,叫按共享傳遞。這要取決於參數的類型。java
ECMAScript 中全部函數的參數都是 按值傳遞的。也就是說,把函數外部的值複製給函數內部的參數,就和把值從一個變量複製到另外一個變量同樣。 基本類型值的傳遞如同基本類型變量的複製同樣,而 引用類型值的傳遞,則如同引用類型變量的複製同樣。-- 《JavaScript高級程序設計》
紅寶書上講全部函數的參數都是按值傳遞的,究竟是不是呢?讓咱們分析下上面的栗子:es6
JavaScript中基本類型做爲參數的策略爲 按值傳遞(call by value):函數
function foo(a) { a = a * 10; } var num = 10; foo(num); console.log(num); // 10 沒有變化
這裏看到函數內部參數的改變並無影響到外部變量。按值傳遞沒錯。設計
JavaScript中對象做爲參數傳遞的策略爲 按共享傳遞(call by sharing):code
按上面栗子函數內部修改了參數b
的屬性item
,會影響到函數外部對象,於是obj1
的屬性item
也變了。對象
function bar(b) { b.item = "changed"; console.log(b === obj1) // true } var obj1 = {item: "unchanged"}; bar(obj1); console.log(obj1.item); // changed 修改參數的屬性將會影響到外部對象
從b === obj1
打印結果爲true
能夠看出,函數內部修改了參數的屬性並無影響到參數的引用。b
和obj1
共享一個對象地址,因此修改參數的屬性將會影響到外部對象。ip
而將參數c
從新賦值一個新對象,將不會影響到外部對象。get
function baz(c) { c = {item: "changed"}; console.log(c === obj2) // false } var obj2 = {item: "unchanged"}; baz(obj2); console.log(obj2.item); // unchanged 從新賦值將不會影響到外部對象
將參數c
從新賦值一個新對象,那麼c
就綁定到了一個新的對象地址,c === obj2
打印結果爲false
,判斷他們再也不共享同一個對象地址。它們各自有獨立的對象地址。因此從新賦值將不會影響到外部對象。it
能夠說 按共享傳遞 是 按值傳遞 的特例,傳遞的是引用地址的拷貝。因此紅寶書上說的也沒錯。
能夠把 ECMAScript 函數的參數想象成局部變量。-- 《JavaScript高級程序設計》
前面瞭解到了全部函數的參數都是按值傳遞的。JavaScript 中參數是必須先求值再做爲實參傳入函數的。可是在ES6中有一個特例。
參數默認值不是傳值的,而是每次都從新計算默認值表達式的值。也就是說,參數默認值是 惰性求值的。 -- 《ECMAScript 6 入門》
let x = 99; function foo(p = x + 1) { console.log(p); } foo() // 100 x = 100; foo() // 101
上面代碼中,參數p
的默認值是x + 1
。這時,每次調用函數foo
,都會從新計算x + 1
,而不是默認p
等於 100。
Is JavaScript a pass-by-reference or pass-by-value language?