协慌网

登录 贡献 社区

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

原始类型(Number,String 等)按值传递,但是对象是未知的,因为它们可以是值传递(如果我们认为持有对象的变量实际上是对象的引用)并且通过引用传递(当我们认为对象的变量保存对象本身时)。

虽然最后并不重要,但我想知道提交传递约定的参数的正确方法是什么。是否有 JavaScript 规范的摘录,它定义了与此相关的语义?

答案

它在 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
  • 如果它是纯值传递值,则更改obj1.item对函数外部的obj1没有影响。
  • 如果它是纯粹的参考传递,那么一切都会改变。 num将为100obj2.item将显示为"changed"

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

实际上,这意味着如果您更改参数本身(与numobj2 ),则不会影响输入参数的项目。但是如果你更改参数的INTERNALS ,它将传播回来(与obj1 )。

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

例:

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

function changeMember(x) {
  x.member = "bar";
  alert("in changeMember: " + x.member);
}

var x = {member:"foo"};

alert("before changeObject: " + x.member);
changeObject(x);
alert("after changeObject: " + x.member); /* change did not persist */

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

输出:

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

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

变量不 “保持” 对象,它保存一个引用。您可以将该引用分配给另一个变量,现在它们都引用同一个对象。它总是按值传递(即使该值是参考值......)。

没有办法改变作为参数传递的变量所持有的值,如果 JS 支持通过引用传递,这将是可能的。