基元类型(数字、字符串等)是通过值传递的,但对象是未知的,因为它们既可以通过值传递(如果我们认为持有对象的变量实际上是对对象的引用),也可以通过引用传递(当我们认为对象的变量持有对象本身)。
虽然最后这并不重要,但我想知道通过约定来表达论点的正确方式是什么。是否有JavaScript规范的摘录,该规范定义了与此相关的语义?
基元类型(数字、字符串等)是通过值传递的,但对象是未知的,因为它们既可以通过值传递(如果我们认为持有对象的变量实际上是对对象的引用),也可以通过引用传递(当我们认为对象的变量持有对象本身)。
虽然最后这并不重要,但我想知道通过约定来表达论点的正确方式是什么。是否有JavaScript规范的摘录,该规范定义了与此相关的语义?
当前回答
MDN文档对其进行了清晰的解释,但并不过于冗长:
函数调用的参数是函数的参数。参数按值传递给函数。如果功能发生变化参数的值,此更改不会在全局或调用函数。但是,对象引用也是值,并且它们是特殊的:如果函数更改引用对象的财产,该更改在函数外部可见,(…)
资料来源:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions#Description
其他回答
分享我对JavaScript中引用的了解
在JavaScript中,当将对象分配给变量时,分配给变量的值是对对象的引用:
变量a={a: 1中,b: 2,c: 3个};变量b=a;//b.c是指交流值console.log(b.c)//输出:3//更改b.c值b.c=4//也会更改交流值console.log(a.c)//输出:4
JavaScript总是按值传递;一切都是价值型的。
对象是值,对象的成员函数本身是值(请记住,函数是JavaScript中的一级对象)。此外,关于JavaScript中的一切都是一个对象的概念;这是错误的。字符串、符号、数字、布尔值、空值和未定义值都是基元。
有时,他们可以利用从基本原型继承的一些成员函数和财产,但这只是为了方便。这并不意味着它们本身就是对象。请尝试以下操作以供参考:
x=“测试”;console.log(x.foo);x.foo=12;console.log(x.foo);
在两个console.log中,您都会发现值未定义。
字符串、数字等基本类型变量始终作为传递按价值计算。基于这两个条件,数组和对象作为引用传递或值传递。如果要使用新的Object或array更改该Object或array的值,则它将通过value传递。object1={item:“car”};数组1=[1,2,3];此处是将新对象或数组分配给旧对象或数组。您没有更改属性的值旧对象的。因此它是按值传递的。如果要更改对象或数组的属性值,则会通过引用传递。object1.key1=“汽车”;阵列1[0]=9;此处您正在更改旧对象的属性值。您没有将新对象或数组分配给旧对象或数组。因此它是通过引用传递的。
Code
function passVar(object1, object2, number1) {
object1.key1= "laptop";
object2 = {
key2: "computer"
};
number1 = number1 + 1;
}
var object1 = {
key1: "car"
};
var object2 = {
key2: "bike"
};
var number1 = 10;
passVar(object1, object2, number1);
console.log(object1.key1);
console.log(object2.key2);
console.log(number1);
Output: -
laptop
bike
10
这些短语/概念最初是在JS创建之前很久定义的,它们没有准确描述javascript的语义。我认为尝试将它们应用于JS会导致更多的困惑。
所以不要被“通过引用/值传递”挂断。
考虑以下事项:
变量是指向值的指针。重新分配变量只会将指针指向新值。重新分配变量不会影响指向同一对象的其他变量,因为每个变量都有自己的指针。
所以如果我必须给它起个名字,我会说“passbypointer”——我们不处理JS中的指针,但底层引擎会处理。
// code
var obj = {
name: 'Fred',
num: 1
};
// illustration
'Fred'
/
/
(obj) ---- {}
\
\
1
// code
obj.name = 'George';
// illustration
'Fred'
(obj) ---- {} ----- 'George'
\
\
1
// code
obj = {};
// illustration
'Fred'
(obj) {} ----- 'George'
| \
| \
{ } 1
// code
var obj = {
text: 'Hello world!'
};
/* function parameters get their own pointer to
* the arguments that are passed in, just like any other variable */
someFunc(obj);
// illustration
(caller scope) (someFunc scope)
\ /
\ /
\ /
\ /
\ /
{ }
|
|
|
'Hello world'
一些最终意见:
短语“传递值/引用”仅用于描述语言的行为,不一定是实际的底层实现。由于这种抽象,对于正确解释至关重要的关键细节丢失了,这不可避免地导致了当前的情况,在没有额外信息的情况下,单个术语无法充分描述实际行为。人们很容易认为原语是由特殊规则强制执行的,而对象不是,但原语只是指针链的末端。作为最后一个示例,请考虑为什么清除数组的常见尝试不能按预期工作。
变量a=[1,2];变量b=a;a=[];console.log(b);//[1,2]//不起作用,因为“b”仍指向原始数组
对于编程语言律师,我已经阅读了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版中定义了“对象是财产的集合”。因此,我们可以推断,对象的值是集合,但是关于集合的值是什么,在规范中定义得很差,需要一些努力才能理解。