基元类型(数字、字符串等)是通过值传递的,但对象是未知的,因为它们既可以通过值传递(如果我们认为持有对象的变量实际上是对对象的引用),也可以通过引用传递(当我们认为对象的变量持有对象本身)。
虽然最后这并不重要,但我想知道通过约定来表达论点的正确方式是什么。是否有JavaScript规范的摘录,该规范定义了与此相关的语义?
基元类型(数字、字符串等)是通过值传递的,但对象是未知的,因为它们既可以通过值传递(如果我们认为持有对象的变量实际上是对对象的引用),也可以通过引用传递(当我们认为对象的变量持有对象本身)。
虽然最后这并不重要,但我想知道通过约定来表达论点的正确方式是什么。是否有JavaScript规范的摘录,该规范定义了与此相关的语义?
当前回答
它总是按值传递,但对于对象,变量的值是一个引用。因此,当您传递一个对象并更改其成员时,这些更改将在函数之外持续存在。这使得它看起来像是通过引用传递。但如果您实际更改了对象变量的值,您将看到更改不会持续,这证明它确实是通过值传递的。
例子:
函数changeObject(x){x={member:“bar”};console.log(“in changeObject:”+x.member);}函数changeMember(x){x.member=“bar”;console.log(“in changeMember:”+x.member);}var x={member:“foo”};console.log(“before changeObject:”+x.member);changeObject(x);console.log(“after changeObject:”+x.member);/*更改没有持续*/console.log(“changeMember之前:”+x.member);changeMember(x);console.log(“after changeMember:”+x.member);/*更改持续存在*/
输出:
before changeObject: foo
in changeObject: bar
after changeObject: foo
before changeMember: foo
in changeMember: bar
after changeMember: bar
其他回答
这样想:它总是通过价值传递。然而,对象的值不是对象本身,而是对该对象的引用。
下面是一个例子,传递一个数字(一个原始类型)
function changePrimitive(val) {
// At this point there are two '10's in memory.
// Changing one won't affect the other
val = val * 10;
}
var x = 10;
changePrimitive(x);
// x === 10
对对象重复此操作会产生不同的结果:
function changeObject(obj) {
// At this point there are two references (x and obj) in memory,
// but these both point to the same object.
// changing the object will change the underlying object that
// x and obj both hold a reference to.
obj.val = obj.val * 10;
}
var x = { val: 10 };
changeObject(x);
// x === { val: 100 }
再举一个例子:
function changeObject(obj) {
// Again there are two references (x and obj) in memory,
// these both point to the same object.
// now we create a completely new object and assign it.
// obj's reference now points to the new object.
// x's reference doesn't change.
obj = { val: 100 };
}
var x = { val: 10 };
changeObject(x);
// x === { val: 10}
我在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
也就是说,基本类型是通过值传递的,复杂类型是通过引用传递的。
我会说这是通过复印件传递的-
考虑参数和变量对象是在函数调用开始时创建的执行上下文中创建的对象,传递到函数中的实际值/引用只存储在这个参数+变量对象中。
简单地说,对于基元类型,值在函数调用开始时被复制,对于对象类型,引用被复制。
这些短语/概念最初是在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”仍指向原始数组
“JavaScript:最终指南”一书的这一章对复制、传递和比较值和引用进行了非常详细的解释。
在我们离开主题之前操作对象和阵列参考,我们需要澄清一点术语。短语“路过”“引用”可以有几种含义。对一些读者来说,这个短语指的是一种函数调用技术允许函数分配新值它的论点,并拥有这些外部可见的修改值作用这不是术语的方式本书中使用了。这里,我们的意思是简单地说,对对象的引用或数组--而不是对象本身--传递给函数。A函数可以使用引用修改对象或元素的财产阵列的。但如果函数用对新对象或阵列的引用,该修改不可见在功能之外。读者熟悉这个词可能更喜欢这样说对象和数组值,但传递的值为实际上是一个参考,而不是对象本身。