基元类型(数字、字符串等)是通过值传递的,但对象是未知的,因为它们既可以通过值传递(如果我们认为持有对象的变量实际上是对对象的引用),也可以通过引用传递(当我们认为对象的变量持有对象本身)。
虽然最后这并不重要,但我想知道通过约定来表达论点的正确方式是什么。是否有JavaScript规范的摘录,该规范定义了与此相关的语义?
基元类型(数字、字符串等)是通过值传递的,但对象是未知的,因为它们既可以通过值传递(如果我们认为持有对象的变量实际上是对对象的引用),也可以通过引用传递(当我们认为对象的变量持有对象本身)。
虽然最后这并不重要,但我想知道通过约定来表达论点的正确方式是什么。是否有JavaScript规范的摘录,该规范定义了与此相关的语义?
当前回答
对于编程语言律师,我已经阅读了ECMAScript 5.1的以下部分(它比最新版本更容易阅读),并在ECMASript邮件列表中询问了它。
TL;DR:一切都是通过值传递的,但Objects的财产是引用,标准中令人毛骨悚然地缺少Object的定义。
参数列表的构造
第11.2.4节“参数列表”说明了生成仅由1个参数组成的参数列表的以下内容:
生产ArgumentList:AssignmentExpression的计算如下:让ref是赋值表达式的结果。让arg为GetValue(ref)。返回唯一项为arg的列表。
本节还列举了参数列表包含0或>1个参数的情况。
因此,所有的都是通过引用传递的。
对象财产的访问
第11.2.1节“财产访问人”
生产MemberExpression:MemberExpression[Expression]的计算如下:让baseReference作为计算MemberExpression的结果。让baseValue为GetValue(baseReference)。让propertyNameReference作为表达式求值的结果。让propertyNameValue为GetValue(propertyNameReference)。调用CheckObject强制(baseValue)。让propertyNameString为ToString(propertyNameValue)。如果正在计算的语法生成包含在严格模式代码中,则让strict为true,否则让严格是假的。返回一个Reference类型的值,其基值为baseValue,其引用名称为propertyNameString,其严格模式标志为strict。
因此,对象的财产始终可用作参考。
关于参考
第8.7节“引用规范类型”中描述了引用在语言中不是真正的类型——它们仅用于描述删除行为、类型和赋值运算符。
“对象”的定义
5.1版中定义了“对象是财产的集合”。因此,我们可以推断,对象的值是集合,但是关于集合的值是什么,在规范中定义得很差,需要一些努力才能理解。
其他回答
一切都是通过价值传递的。
基本类型按值传递(即,实际变量值的新副本传递给函数)。
复杂类型(对象)作为“对象指针”传递。因此,您传递的实际内容是一个指针,它是按值传递的(它是一个地址,一个像任何其他值一样的数值)。显然,如果您试图在函数内修改对象的属性,那么即使在该函数外,修改也会反映出来。这是因为您通过指向属性唯一副本的指针访问属性。
这里的混淆出现在“通过值传递指针”和“通过引用传递对象”上。
基本体(数字、布尔值等)按值传递。字符串是不可变的,所以对它们来说并不重要。对象通过引用传递(引用通过值传递)。
我在AirBNB风格指南中找到了最简洁的解释:
基本体:访问基本体类型时,直接处理其价值一串数字布尔型无效的未定义
例如。:
var foo = 1,
bar = foo;
bar = 9;
console.log(foo, bar); // => 1, 9
复杂:访问复杂类型时,需要处理对其值的引用对象大堆作用
例如。:
var foo = [1, 2],
bar = foo;
bar[0] = 9;
console.log(foo[0], bar[0]); // => 9, 9
也就是说,基本类型是通过值传递的,复杂类型是通过引用传递的。
这是对值传递和引用传递(JavaScript)的更多解释。在这个概念中,他们讨论的是通过引用传递变量和通过引用传递该变量。
传递值(基本类型)
var a = 3;
var b = a;
console.log(a); // a = 3
console.log(b); // b = 3
a=4;
console.log(a); // a = 4
console.log(b); // b = 3
应用于JavaScript中的所有基元类型(字符串、数字、布尔值、未定义和null)。a被分配一个存储器(例如0x001),b在存储器中创建该值的拷贝(例如0x002)。因此,更改一个变量的值不会影响另一个变量,因为它们都位于两个不同的位置。
通过引用(对象)
var c = { "name" : "john" };
var d = c;
console.log(c); // { "name" : "john" }
console.log(d); // { "name" : "john" }
c.name = "doe";
console.log(c); // { "name" : "doe" }
console.log(d); // { "name" : "doe" }
JavaScript引擎将对象分配给变量c,并指向某个内存,例如(0x012)。当d=c时,在该步骤中,d指向相同的位置(0x012)。更改任何变量的值都会更改这两个变量的值。函数是对象
特殊情况,通过引用传递(对象)
c = {"name" : "jane"};
console.log(c); // { "name" : "jane" }
console.log(d); // { "name" : "doe" }
等号(=)运算符设置新的内存空间或地址
通过引用外部对象,将函数外部的对象传递到函数中。
当使用该引用操纵其对象时,外部的对象将受到影响。但是,如果在函数内部决定将引用指向其他对象,则根本不会影响外部对象,因为所做的只是将引用重新指向其他对象。