在JavaScript中为传递给函数的对象赋值
我是JavaScript新手(虽然对C++有经验),今天,我写了如下内容:在JavaScript中为传递给函数的对象赋值,javascript,pass-by-reference,pass-by-value,Javascript,Pass By Reference,Pass By Value,我是JavaScript新手(虽然对C++有经验),今天,我写了如下内容: function foo(bar) { bar = "something else"; } var x = "blah"; foo(x); alert(x); // Alerts with "blah", but I was expecting it to alert with "something else" 这让我很困惑,因为我一直在看Douglas Crockford的一些JavaScript视频,还记得
function foo(bar) {
bar = "something else";
}
var x = "blah";
foo(x);
alert(x); // Alerts with "blah", but I was expecting it to alert with "something else"
这让我很困惑,因为我一直在看Douglas Crockford的一些JavaScript视频,还记得他说过“JavaScript总是通过引用传递”之类的话
我可以解释这种情况的方式是JavaScript将引用传递给对象,但这些引用是复制的。这意味着在foo
函数中,我为bar
分配了一个新的引用,该引用随后超出了范围,留下了未触及的x
引用。基本上,我们从以下方面开始:
x ---->"blah"
然后,当调用foo
时,bar
引用相同的数据:
x ---->"blah"
bar -----^
因此,当将“其他内容”分配给条时,会发生以下情况:
x ---->"blah"
bar ---->"something else"
这是JavaScript中实际发生的事情的准确模型,还是我遗漏了其他东西
作为一个额外的问题,有没有办法说,更改这个变量引用的数据?这是一种经常出现的情况,还是很容易避免
编辑:
Douglas Crockford在文章中说“对象总是通过引用传递,而不是通过值传递”,这是正确的,但是函数的参数是通过值传递的,只是引用是通过值传递的。您的解释是正确的
您可以更改对象中关键点的值,这使您可以执行类似于按引用传递的操作:
function foo(bar) {
bar.msg = "something else";
}
var x = { msg: "blah" };
foo(x);
alert(x.msg);
数字、字符串等基本值不是通过引用传递的,而是通过对象传递的。例如:
var myObj = {
value: "Hello"
};
function change(localObj) {
localObj.value = "Bye";
}
change(myObj);
console.log(myObj.value) // Prompts "Bye"
var x = {Value: "blah"};
foo(x);
你的解释恰到好处
首先,您有一个名为x
的变量,它是对字符串对象的引用。假设内存是0x100x
指向0x100
,其中包含以下字节:
接下来,将0x100
传递到函数foo
:
function foo(bar) {
bar = "something else";
}
由于JavaScript中的所有内容都是按值传递的,即使是引用,JavaScript也会在内存中复制该引用,现在在该函数中称为bar
:
foo(x); // Copies the value of x (a reference) to bar
在这一点上,我们有两个独立的变量<代码>x
和条
。两者恰好具有相同的值,0x100
。因此,如果要更改对象的某个属性(其中一个是引用对象),它将同时影响x
和bar
但是,您要做的是指定条
指向其他内容:
bar = "something else"; // Now references some other string we just created
现在,bar
被重新分配来引用我们刚刚分配内存的新字符串bar
的值不再是0x100
,它现在有一个其他地址的值(比如0x500
)x
当然还有一个值0x100
,因为bar
只是x
的副本,而不是x
的引用
因此,当您:
alert(x);
您仍然会得到原始值,因为这就是x
所指向的
第二个问题:
有没有办法说,更改此变量引用的数据?
这是一种经常出现的情况,还是很容易避免
是的,用另一个物体把它包起来。例如:
var myObj = {
value: "Hello"
};
function change(localObj) {
localObj.value = "Bye";
}
change(myObj);
console.log(myObj.value) // Prompts "Bye"
var x = {Value: "blah"};
foo(x);
现在,我们有一个对对象的引用,该对象具有一个名为Value
的属性,其中包含对内存中某个字符串的引用
在foo
中,我们可以执行以下操作:
bar.Value = "something else";
这将影响x
的Value
属性,因为bar
和x
都引用了相同的对象,并且您从未更改过其中任何一个的值
换句话说,您不能重新分配传递到函数中的引用,因为您只是重新分配了一个副本。但是,您可以更改被引用对象的属性,因为该引用的其他副本都指向您正在更改的数据。“JavaScript总是通过引用传递”是一个善意的谎言和术语混淆。虽然有一些“灰色地带”,我还是经过
以下是我的论点和推理。如果您持有不同的观点,请确保您至少能够支持它
通过引用调用意味着(对许多人来说)分配给参数会影响调用者中的绑定
在按引用调用求值(也称为按引用传递)中,函数接收对用作参数的变量的隐式引用,而不是其值的副本。这通常意味着函数可以修改(即赋值)用作参数的变量,调用方将看到该变量
JavaScript中并非如此,正如原始帖子在观察到的行为中所指出的那样。重新分配参数(可以将其视为具有动态提供的值的局部变量)不会影响任何提供的参数
有时,“引用调用”被[令人困惑地]用来表示“共享调用”或“引用值调用”,如下所述;在C++和VB等语言中发现了真正的引用调用,而不是JavaScript。
JavaScript的调用约定可以完全从语义的角度进行讨论。 所有JavaScript对象都是值;所有的原语值(是所有值的子集)都是不可变的 通过共享调用的语义与通过引用调用的语义不同,因为调用方看不到函数中函数参数的赋值,因此,例如,如果传递了变量,则不可能在调用方的作用域中模拟对该变量的赋值。但是,由于函数可以访问与调用方相同的对象(不复制),因此调用方可以看到函数中这些对象的变化(如果对象是可变的),这可能与按值调用语义不同 ultrayoshi的答案a中提供了这些共享突变的一个例子