基元类型(数字、字符串等)是通过值传递的,但对象是未知的,因为它们既可以通过值传递(如果我们认为持有对象的变量实际上是对对象的引用),也可以通过引用传递(当我们认为对象的变量持有对象本身)。

虽然最后这并不重要,但我想知道通过约定来表达论点的正确方式是什么。是否有JavaScript规范的摘录,该规范定义了与此相关的语义?


当前回答

我在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中向函数传递参数类似于传递参数(按C中的指针值):

/*
The following C program demonstrates how arguments
to JavaScript functions are passed in a way analogous
to pass-by-pointer-value in C. The original JavaScript
test case by @Shog9 follows with the translation of
the code into C. This should make things clear to
those transitioning from C to JavaScript.

function changeStuff(num, obj1, obj2)
{
    num = num * 10;
    obj1.item = "changed";
    obj2 = {item: "changed"};
}

var num = 10;
var obj1 = {item: "unchanged"};
var obj2 = {item: "unchanged"};
changeStuff(num, obj1, obj2);
console.log(num);
console.log(obj1.item);    
console.log(obj2.item);

This produces the output:

10
changed
unchanged
*/

#include <stdio.h>
#include <stdlib.h>

struct obj {
    char *item;
};

void changeStuff(int *num, struct obj *obj1, struct obj *obj2)
{
    // make pointer point to a new memory location
    // holding the new integer value
    int *old_num = num;
    num = malloc(sizeof(int));
    *num = *old_num * 10;
    // make property of structure pointed to by pointer
    // point to the new value
    obj1->item = "changed";
    // make pointer point to a new memory location
    // holding the new structure value
    obj2 = malloc(sizeof(struct obj));
    obj2->item = "changed";
    free(num); // end of scope
    free(obj2); // end of scope
}

int num = 10;
struct obj obj1 = { "unchanged" };
struct obj obj2 = { "unchanged" };

int main()
{
    // pass pointers by value: the pointers
    // will be copied into the argument list
    // of the called function and the copied
    // pointers will point to the same values
    // as the original pointers
    changeStuff(&num, &obj1, &obj2);
    printf("%d\n", num);
    puts(obj1.item);
    puts(obj2.item);
    return 0;
}

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按值传递原语类型,按引用传递对象类型

现在,人们喜欢没完没了地争论是否“通过引用”是描述Java等实际操作的正确方式这是:传递对象不会复制对象。传递给函数的对象可以由该函数修改其成员。传递给函数的基元值不能由该函数修改。复制完成。在我的书中,这叫做通过引用传递。

-Brian Bi-哪些编程语言是通过引用传递的?


使现代化

以下是对此的反驳:

JavaScript中没有可用的“通过引用传递”。

基本体通过值传递,对象通过引用传递。这与C、Visual Basic或Delphi等其他语言截然不同。我不能说它们如何准确地处理对象和原语,但我知道VisualBasic和Delphi可以(也应该)指定它们。

PHP在版本5之后做了类似的事情:所有对象都是通过引用传递的,但所有原语都可以通过引用传递,如果前面有一个与符号(&)。否则,基元按值传递。

所以在JavaScript中,如果我通过一个参数将一个对象X传递给一个函数,它仍然是X。如果你在函数(或任何其他对象,但这并不重要)内部更改数据,那么新值也可以在函数外部使用。