基元类型(数字、字符串等)是通过值传递的,但对象是未知的,因为它们既可以通过值传递(如果我们认为持有对象的变量实际上是对对象的引用),也可以通过引用传递(当我们认为对象的变量持有对象本身)。
虽然最后这并不重要,但我想知道通过约定来表达论点的正确方式是什么。是否有JavaScript规范的摘录,该规范定义了与此相关的语义?
基元类型(数字、字符串等)是通过值传递的,但对象是未知的,因为它们既可以通过值传递(如果我们认为持有对象的变量实际上是对对象的引用),也可以通过引用传递(当我们认为对象的变量持有对象本身)。
虽然最后这并不重要,但我想知道通过约定来表达论点的正确方式是什么。是否有JavaScript规范的摘录,该规范定义了与此相关的语义?
当前回答
JavaScript很有趣。考虑以下示例:
功能更改Stuff(a、b、c){a=a*10;b.项目=“已更改”;c={item:“changed”};}变量num=10;var obj1={item:“未更改”};var obj2={item:“未更改”};changeStuff(num,obj1,obj2);控制台日志(num);console.log(obj1.item);console.log(obj2.item);
这将产生以下输出:
10
changed
unchanged
如果obj1根本不是引用,则更改obj1.item不会对函数外部的obj1产生影响。如果这个论点是正确的参考,那么一切都会改变。num将为100,obj2.item将为“changed”。相反,num保持10,obj2.item保持“不变”。
相反,情况是传入的项是按值传递的。但通过值传递的项本身就是一个引用。从技术上讲,这叫做共享呼叫。
实际上,这意味着如果更改参数本身(如num和obj2),则不会影响输入到参数中的项。但是,如果更改参数的内部结构,则会向上传播(与obj1一样)。
其他回答
函数内部的简单值不会改变函数外部的值(通过值传递),而复杂值会(通过引用传递)。
function willNotChange(x) {
x = 1;
}
var x = 1000;
willNotChange(x);
document.write('After function call, x = ' + x + '<br>'); // Still 1000
function willChange(y) {
y.num = 2;
}
var y = {num: 2000};
willChange(y);
document.write('After function call y.num = ' + y.num + '<br>'); // Now 2, not 2000
JavaScript按值传递原语类型,按引用传递对象类型
现在,人们喜欢没完没了地争论是否“通过引用”是描述Java等实际操作的正确方式这是:传递对象不会复制对象。传递给函数的对象可以由该函数修改其成员。传递给函数的基元值不能由该函数修改。复制完成。在我的书中,这叫做通过引用传递。
-Brian Bi-哪些编程语言是通过引用传递的?
使现代化
以下是对此的反驳:
JavaScript中没有可用的“通过引用传递”。
JavaScript很有趣。考虑以下示例:
功能更改Stuff(a、b、c){a=a*10;b.项目=“已更改”;c={item:“changed”};}变量num=10;var obj1={item:“未更改”};var obj2={item:“未更改”};changeStuff(num,obj1,obj2);控制台日志(num);console.log(obj1.item);console.log(obj2.item);
这将产生以下输出:
10
changed
unchanged
如果obj1根本不是引用,则更改obj1.item不会对函数外部的obj1产生影响。如果这个论点是正确的参考,那么一切都会改变。num将为100,obj2.item将为“changed”。相反,num保持10,obj2.item保持“不变”。
相反,情况是传入的项是按值传递的。但通过值传递的项本身就是一个引用。从技术上讲,这叫做共享呼叫。
实际上,这意味着如果更改参数本身(如num和obj2),则不会影响输入到参数中的项。但是,如果更改参数的内部结构,则会向上传播(与obj1一样)。
观察:如果观察者无法检查引擎的底层内存,则无法确定是否复制了不可变值或传递了引用。
JavaScript或多或少与底层内存模型无关。没有参考²。JavaScript有值。两个变量可以保持相同的值(或者更准确:两个环境记录可以绑定相同的值)。唯一可以变异的值类型是通过抽象[[Get]]和[[Set]]操作的对象。如果您忘记了计算机和内存,这就是描述JavaScript行为所需的全部内容,它可以让您理解规范。
let a = { prop: 1 };
let b = a; // a and b hold the same value
a.prop = "test"; // The object gets mutated, can be observed through both a and b
b = { prop: 2 }; // b holds now a different value
现在你可能会问自己,两个变量如何在计算机上保持相同的值。然后,您可能会查看JavaScript引擎的源代码,很可能会发现引擎所用语言的程序员会调用引用。
所以事实上,你可以说JavaScript是“值传递”,而值可以被共享,你可以称JavaScript是“引用传递”,这对于低级语言的程序员来说可能是一个有用的逻辑抽象,或者你可以将行为称为“共享调用”。
由于JavaScript中没有引用,所有这些都没有错,也没有切中要害。因此,我不认为搜索答案特别有用。
²规范中的术语“参考”不是传统意义上的参考。它是一个对象和属性名称的容器,并且是一个中间值(例如,a.b计算为Reference{value=a,name=“b”})。术语“引用”有时也出现在规范中的不相关章节中。
基本体通过值传递,对象通过引用传递。这与C、Visual Basic或Delphi等其他语言截然不同。我不能说它们如何准确地处理对象和原语,但我知道VisualBasic和Delphi可以(也应该)指定它们。
PHP在版本5之后做了类似的事情:所有对象都是通过引用传递的,但所有原语都可以通过引用传递,如果前面有一个与符号(&)。否则,基元按值传递。
所以在JavaScript中,如果我通过一个参数将一个对象X传递给一个函数,它仍然是X。如果你在函数(或任何其他对象,但这并不重要)内部更改数据,那么新值也可以在函数外部使用。