JavaScript中的函数是按值传递还是按引用传递?

4
我知道在JavaScript中对象是通过引用复制/传递的。但是函数呢?
我在尝试这段代码时遇到了一些困惑,以下是这段代码片段:

x = function() { console.log('hey 1'); }

y = x;

x = function() { console.log('hey 2'); }

y; // Prints function() { console.log('hey 1'); }

如果像对象一样的函数是通过复制/引用传递的,为什么y没有更新以打印“hey 2”?

如果这种行为是因为“x”被赋予了全新的函数,那么在x更改时有没有办法将变量“y”指向新分配的函数?


这种行为与{x:1}{x:2}相同,而不是与function(){console.log('hey 1');}function(){ console.log('hey 2'); }不同。您目前的措辞让人感觉好像您正在观察对象与函数之间的不同模式,但实际上这是不可能的。 - apsillers
在几乎所有编程语言中,我似乎找到了一个常数,即“=”运算符只会修改它所引用的变量(例如,实际引用“x”),而不是底层数据。如果类型具有.modify().add()方法,则这是底层数据可以更改以便通过多个变量可见的一种方式。 - Katana314
抱歉 - 自我警示:在JavaScript中,“=”用于修改对象的属性,这可以被其他引用看到。例如:var b = a; a.myprop = 3; console.log(b.myprop); - Katana314
“如果像对象一样的函数被复制/传递引用,为什么y没有更新以打印'hey 2'?”你正在做出错误的假设。在JavaScript中,所有东西都是按值传递的。” - Felix Kling
3个回答

6

JS中的一切都是按值传递,其中对象和函数的值是一个引用。

这里发生的事情与对象发生的事情相同(因为函数只是一级对象):

以下是正在发生的事情的要点:

x = function() { console.log('hey 1'); }

x 指向 记录1的函数(为此函数创建了内存)

y = x;

y 指向 记录1的函数()(相同的内存位置)

x = function() { console.log('hey 2'); }

x 现在指向一个 新的 function(),记录了2个日志(一个新的内存空间),但是没有影响到 y

y;

y仍然指向同一个记录1的function()


如果您希望对x所做的更改影响到y,您应该更改它们指向的内容,而不是更改它们所指向的东西。

例如:

var pointingAtMe = { log: function() { console.log('1'); } }
var x = pointingAtMe;
var y = pointingAtMe;

// change the actual thing x and y are both pointing to
x.log = function() { console.log('2'); } // this line also sets `y.log` and `pointingAtMe.log`since they all point to the same thing
// and the change gets applied to both
y.log(); // logs '2'

1
如果函数像对象一样被复制/传递引用,为什么y的值没有更新并输出'hey 2'呢?
你做了错误的假设。在JavaScript中,一切都是按值传递的(pass-by-value)。虽然对象被表示为引用,但这与按引用传递是不同的。
即使您使用纯对象而不是函数,也无法看到您期望的结果:
var x = {foo: 42};
var y = x;
x = {foo: 21};
console.log(y.foo); // still 42

传值/传址仅描述了如何解析变量参数,与变量的值无关。

如果这种行为是因为'x'被分配了一个全新的函数,那么当x改变时,有没有办法将变量'y'指向新分配的函数?

没有。除非显式地将y分配给新函数。


0

x = function() { console.log('hey 2'); } 并没有改变 x 变量中包含的对象,而是修改了 x 变量的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接