【问题标题】:How does variable assignment work in JavaScript?变量赋值在 JavaScript 中是如何工作的?
【发布时间】:2010-10-05 07:21:01
【问题描述】:

所以前几天我一直在玩,只是想看看 JavaScript 中批量赋值是如何工作的。

首先我在控制台中尝试了这个例子:

a = b = {};
a.foo = 'bar';
console.log(b.foo);

结果是“条”显示在警报中。这很公平,ab 实际上只是同一个对象的别名。然后我想,我怎样才能让这个例子更简单。

a = b = 'foo';
a = 'bar';
console.log(b);

这几乎是一回事,不是吗?好吧,这一次,它返回 foo 而不是 bar,正如我对第一个示例的行为所期望的那样。

为什么会这样?

注意可以使用以下代码进一步简化此示例:

a = {};
b = a;
a.foo = 'bar';
console.log(b.foo);

a = 'foo';
b = a;
a = 'bar';
console.log(b);

(我怀疑 JavaScript 对字符串和整数等原语的处理与散列不同。散列返回一个指针,而“核心”原语返回其自身的副本)

【问题讨论】:

标签: javascript


【解决方案1】:

您或多或少是正确的,只是您所说的“哈希”实际上只是对象的简写语法。

在第一个例子中,ab 都指向同一个对象。在第二个示例中,您将 a 更改为引用其他内容。

【讨论】:

  • 那么为什么对 Object 有双重标准?
  • 这不是双重标准。在第一个示例中,a 和 b 仍然引用同一个对象,您只是在修改该对象的属性。在第二个示例中,您将 a 指向不同的对象。
  • 不,不同的是,在第二种情况下,您处理的是字符串,而不是对象。
  • 要明确:这与返回自身副本的字符串无关。两个代码 sn-ps 不同的原因在 Kevin 的第二段中(在 Squeegy 的回答中更全面地解释了)。
  • 变量中有字符串还是对象都没有关系。您分配一个新的不同值,然后变量包含该新的不同值。
【解决方案2】:

你正在设置 a 指向一个新的字符串对象,而 b 一直指向旧的字符串对象。

【讨论】:

    【解决方案3】:

    在第一种情况下,您更改了变量中包含的对象的某些属性,在第二种情况下,您为变量分配了一个新值。那是根本不同的事情。变量ab 并没有被第一个赋值神奇地链接起来,它们只是包含同一个对象。在第二个示例中也是如此,直到您为 b 变量分配一个新值。

    【讨论】:

      【解决方案4】:

      在第一个示例中,您正在设置现有对象的属性。在第二个示例中,您正在分配一个全新的对象。

      a = b = {};
      

      ab 现在是指向同一个对象的指针。所以当你这样做时:

      a.foo = 'bar';
      

      它也设置了b.foo,因为ab 指向同一个对象。

      但是!

      如果您改为这样做:

      a = 'bar';
      

      您是说a 现在指向不同的对象。这对a 之前指向的内容没有影响。

      在 JavaScript 中,分配变量和分配属性是两种不同的操作。最好将变量视为指向对象的指针,当您直接分配给变量时,您不会修改任何对象,而只是将变量重新指向不同的对象。

      但是分配一个属性,比如a.foo,会修改a指向的对象。当然,这也会修改指向该对象的所有其他引用,因为它们都指向同一个对象。

      【讨论】:

      • "你是说 a 现在指向不同的对象。"不,不要使用对象这个词。字符串不是 JavaScript 中的对象。
      • 也许字符串在技术上不是 javascript 类型“对象”,但它们可以被认为是 OO 意义上的对象。
      • @Squeegy:字符串是原语,而不是对象:您不能为字符串分配任意属性!由于 Java 中所谓的自动装箱,它们只会表现得像对象
      • 但是字符串有方法和属性,而且String的原型肯定是可以修改的。它们确实像物体一样。
      • @ddlshack:正如 Christoph 解释的那样,这是由于自动装箱。如果您要通过var foo = new String('foo'); 定义一个字符串,那么 that 将是一个字符串对象(typeof 将确认这一点)。但是,如果您通过字符串文字声明它,那么它们就是字符串原语。见:developer.mozilla.org/en/JavaScript/Reference/Global_Objects/…
      【解决方案5】:

      区别在于简单类型和对象。

      任何对象(如数组或函数)都是通过引用传递的。

      任何简单类型(如字符串或数字)都会被复制。

      我总是有一个方便的 copyArray 函数,所以我可以确定我没有为同一个数组创建一堆别名。

      【讨论】:

      • 这种差异在很多场景下并不明显,但Javascript实际上并没有通过引用传递或赋值。它复制参考值。
      • 这些家伙已经做了很好的解释了,所以我只是粘贴链接:stackoverflow.com/questions/40480/is-java-pass-by-reference(我指的是Java,但是传递和分配值/引用的语义是相同的和 Javascript 一样)
      • 其实这个答案是不正确的,在JavaScript中一切都是按值传递的。来自 MDN,“函数调用的参数是函数的参数。参数按值传递给函数。如果函数更改参数的值,则此更改不会在全局或调用函数中反映出来。但是,对象引用是值也是如此,而且它们很特殊:如果函数更改了引用对象的属性,那么该更改在函数之外是可见的。” developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
      • 基元的行为类似于不可变对象(完全就像它们在严格模式下一样)。这个答案不正确。
      【解决方案6】:

      Squeegy 已经令人满意地回答了您的问题 - 它与对象与基元无关,而是与变量的重新分配与在同一引用对象中设置属性有关。

      答案和cmets中似乎对JavaScript类型有很多混淆,所以这里对JavaScript的类型系统做一个小介绍:

      在 JavaScript 中,有两种根本不同的值:基元和对象(没有像“哈希”这样的东西)。

      字符串、数字和布尔值以及nullundefined 都是原语,对象是所有可以具有属性的东西。甚至数组和函数也是常规对象,因此可以包含任意属性。它们只是在内部 [[Class]] 属性上有所不同(函数还有一个名为 [[Call]] 和 [[Construct]] 的属性,但是,嘿,这是细节)。

      原始值可能表现得像对象的原因是因为自动装箱,但原始值本身不能保存任何属性。

      这是一个例子:

      var a = 'quux';
      a.foo = 'bar';
      document.writeln(a.foo);
      

      这将输出undefineda 包含一个原始值,在分配属性foo 时将其提升为一个对象。但是这个新对象马上就被丢弃了,所以foo的值就丢失了。

      这样想:

      var a = 'quux';
      new String(a).foo = 'bar'; // we never save this new object anywhere!
      document.writeln(new String(a).foo); // a completly new object gets created
      

      【讨论】:

      • Mozilla 基金会的页面 'A re-introduction to JavaScript (JS tutorial)' 将 JavaScript 对象描述为“作为名称-值对的简单集合。因此,它们类似于...”,然后接下来是来自各种编程语言的字典、哈希、哈希表和哈希映射的列表。同一页面将对象属性引用描述为哈希表查找。所以对象就像一个“哈希”表。这并没有否定其他有用的信息,但 Chris Lloyd 的原始描述并非不准确。
      【解决方案7】:

      这是我的答案:

      obj = {a:"hello",b:"goodbye"}
      x = obj
      x.a = "bonjour"
      
      // now obj.a is equal to "bonjour"
      // because x has the same reference in memory as obj
      // but if I write:
      x = {}
      x.a = obj.a
      x.b = obj.b
      x.a = "bonjour"
      
      // now x = {a:"bonjour", b:"goodbye"} and obj = {a:"hello", b:"goodbye"}
      // because x points to another place in the memory
      

      【讨论】:

        猜你喜欢
        • 2012-07-23
        • 1970-01-01
        • 2011-05-25
        • 2011-11-05
        • 2011-12-16
        • 2019-03-25
        • 2016-03-26
        相关资源
        最近更新 更多