最近在研究 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):post
function foo(a) {
a = a * 10;
}
var num = 10;
foo(num);
console.log(num); // 10 没有变化
复制代码
这里看到函数内部参数的改变并无影响到外部变量。按值传递没错。ui
JavaScript中对象做为参数传递的策略为 按共享传递(call by sharing):spa
按上面栗子函数内部修改了参数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
共享一个对象地址,因此修改参数的属性将会影响到外部对象。code
而将参数c
从新赋值一个新对象,将不会影响到外部对象。对象
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
,判断他们再也不共享同一个对象地址。它们各自有独立的对象地址。因此从新赋值将不会影响到外部对象。
能够说 按共享传递 是 按值传递 的特例,传递的是引用地址的拷贝。因此红宝书上说的也没错。
能够把 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?