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

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

虽然最后并不重要,但我想知道通过约定来呈现论点的正确方法是什么。是否有来自JavaScript规范的摘录,它定义了关于此的语义应该是什么?


答案 1

这在JavaScript中很有趣。请考虑以下示例:

function changeStuff(a, b, c)
{
  a = a * 10;
  b.item = "changed";
  c = {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);

这将生成输出:

10
changed
unchanged
  • 如果 根本不是引用,则更改不会对函数外部产生任何影响。obj1obj1.itemobj1
  • 如果这个论点是正确的参考,那么一切都会改变。 将是 ,并将读作 。相反,留下来并保持”。num100obj2.item"changed"num10obj2.item"unchanged

相反,情况是传入的项目是按值传递的。但是,按值传递的项本身就是一个引用。从技术上讲,这称为逐个共享调用

实际上,这意味着如果更改参数本身(如 and ),则不会影响馈送到参数中的项。但是,如果更改参数的内部结构,则会向上传播(与 )。numobj2obj1


答案 2

它始终按值传递,但对于对象,变量的值是引用。因此,当您传递对象并更改其成员时,这些更改将保留在函数之外。这使得它看起来像通过引用传递。但是,如果您实际更改了对象变量的值,您将看到更改不会持续存在,从而证明它确实是按值传递的。

例:

function changeObject(x) {
  x = { member: "bar" };
  console.log("in changeObject: " + x.member);
}

function 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); /* change did not persist */

console.log("before changeMember: " + x.member);
changeMember(x);
console.log("after changeMember: " + x.member); /* change persists */

输出:

before changeObject: foo
in changeObject: bar
after changeObject: foo

before changeMember: foo
in changeMember: bar
after changeMember: bar