JavaScript 是一种按引用传递还是按值传递的语言?

1756

原始类型(例如数字、字符串等)通过值传递,但对象不同,因为它们既可以按值传递(在这种情况下,我们认为保存对象的变量实际上是对该对象的引用),也可以按引用传递(当我们认为变量对对象本身持有该对象时)。

虽然最终并不重要,但我想知道呈现参数传递约定的正确方式是什么。是否有来自JavaScript规范的节选,定义了关于此事应该是什么语义?


8
我认为你不小心颠倒了传值和传引用的定义... "传值(如果我们认为一个变量持有一个对象实际上是指向该对象的引用),传引用(当我们认为变量持有对象本身时)" - Niko Bellic
11
是的。无论在任何编程语言中的函数调用中语法如何,传递引用都表示传递的变量所关联的数据在传递到函数时不会被复制,因此函数对传递的变量所做的任何修改将在函数调用终止后保留在程序中。传值则意味着将变量相关的数据实际上复制到函数中传递,当变量超出函数体作用域并且函数返回时,该函数对变量所做的任何修改都将丢失。 - John Sonderson
9
这个老问题有点棘手,因为它的得票最高的答案是错误的。JavaScript 严格来说是“按值传递”。 - Pointy
9
术语令人遗憾地令人困惑。事实上,“传值”和“传引用”这些术语比许多更现代的编程语言特性还要早。 “值”和“引用”这两个词 具体 指函数调用表达式中的参数。JavaScript始终在调用函数之前计算函数调用参数列表中的每个表达式,因此参数始终是值。令人困惑的是,对象的引用是常见的JavaScript值。然而,这并不意味着它是一种“传引用”的语言。 - Pointy
4
“按引用传递”特指以下情况:如果你有var x=3, y=x; f(x); alert(y === x);,那么函数f()可以使得alert报告false而不是true。在JavaScript中,这是不可能的,所以它不是“按引用传递”。能够传递可修改对象的引用是好的,但这并不是“按引用传递”的意思。就像我说的,术语混淆真是令人遗憾。 - Pointy
显示剩余12条评论
35个回答

-3

判断一个变量是否是“按引用传递”的简单方法是看你是否可以编写一个“交换”函数。例如,在C语言中,你可以这样做:

void swap(int *i, int *j)
{
    int t;
    t = *i;
    *i = *j;
    *j = t;
}

如果你在JavaScript中不能做到相当于这个的操作,那就不是“按引用传递”。

22
这并不是真正的按引用传递。你正在将指针传递给函数,而这些指针是按值传递的。更好的例子是C++中的&运算符或C#中的"ref"关键字,它们都是真正的按引用传递。 - Matt Greer
更容易的是,在JavaScript中所有东西都是按值传递的。 - Scott Marcus
https://dev59.com/tp7ha4cB1Zd3GeqPpdnm#42045636 - Scott Marcus

-4
  1. 像字符串、数字这样的原始类型变量总是按值传递。
  2. 数组和对象根据以下两个条件之一进行按引用传递或按值传递。

    • 如果您使用新对象或数组更改该对象或数组的值,则它将按值传递。

      object1 = {item: "car"}; array1=[1,2,3];

    在这里,您将新对象或数组分配给旧对象。您没有更改旧对象的属性值,因此它是按值传递。

    • 如果您更改对象或数组的属性值,则它将按引用传递。

      object1.key1= "car"; array1[0]=9;

    在这里,您更改了旧对象的属性值。您没有将新对象或数组分配给旧对象,因此它是按引用传递。

代码

    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

1
赋值运算符不应与函数调用混淆。当您将新数据分配给现有变量时,旧数据的引用计数减少,并将新数据与旧变量相关联。基本上,变量最终指向新数据。属性变量也是如此。由于这些赋值不是函数调用,因此与传值或传引用无关。 - John Sonderson
1
不,所有东西都是按值传递的。这只取决于你传递的是什么(一个值还是一个引用)。请参见此链接 - Scott Marcus

-5

关于在JavaScript中使用术语“按引用传递”的讨论在这里,但是为了回答你的问题:

对象会自动按引用传递,无需特别声明

(来自上述文章。)


7
该链接的文章不再包含上述陈述,并避免使用“按引用传递”的术语。 - C Perkins
该值是一个引用。 - user985399

-5

原始类型按值传递,而对象按引用传递。这与其他语言(如C、Visual Basic或Delphi)非常不同。我无法确切地说它们如何处理对象和原始类型,但我知道Visual Basic和Delphi可以(并且应该)指定。

自版本5以来,PHP做了类似的事情:所有对象都是按引用传递的,但如果在原始类型之前加上一个&符号,那么所有原始类型可能也会被按引用传递。否则,原始类型将按值传递。

因此,在JavaScript中,如果我通过参数将对象X传递到函数中,它仍然是X。如果您在函数内部更改数据(或任何其他对象,但这并不重要),则该新值也可在函数外部使用。


这是错误的。请参见http://jsfiddle.net/rdarc/。该值未更改,而是更改了引用。新值在函数外也不可用。 - Tom
@Tom,将你的代码更改为`var x = {hi : 'hi'}; change(x); console.log(x.hi);function change(x) { x.hi = 'changed'; }`会改变行为。 - Olgun Kaya
https://dev59.com/tp7ha4cB1Zd3GeqPpdnm#42045636 - Scott Marcus

-5

函数内的简单值不会改变函数外的那些值(它们是按值传递的),而复杂值会改变(它们是按引用传递的)。

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

这太荒谬了,y会因为函数级作用域而改变,它被提升并不是因为它是按引用传递的。 - Parijat Kalia
不,所有东西都是按值传递的。这只取决于你传递的是什么(一个值还是一个引用)。请参见此链接 - Scott Marcus

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接