【问题标题】:Setting a variable equal to another variable [duplicate]将变量设置为等于另一个变量[重复]
【发布时间】:2018-11-23 05:11:42
【问题描述】:

我有几个关于在 JavaScript 中设置一个变量等于另一个变量的问题。

假设我们创建一个对象a 并设置b = a

var a = {
  fname: "Jon",
  lname: "Smith",
  age: 50
}

var b = a;

我了解,如果我们更改 a 的属性之一,b 也会被更改,因为当我们设置 b = a 时,我们不会克隆 a 的数据,而是创建对 @ 的引用987654328@的数据。比如我们设置a.fname = "Sarah",那么b.fname的新值就是"Sarah"

如果我们尝试通过设置a = {} 来“清除”a,对象b 将保持不变。我不明白为什么以这种方式操作对象会产生与第一个示例不同的结果。


我还有一个关于以下场景的问题。

var x = 10;
var z = x;

如果我们随后设置x = 20z 的值将保持不变。根据我在第一个问题中描述的行为,人们会认为z 的新值将反映x 的新值。有人可以解释一下我在这里缺少什么吗?

谢谢!

【问题讨论】:

  • x = 10, 10 是数字,像字符串一样原始,原始没有引用,a = {}, {} 是一个新对象,有一个新引用,所以你改变了保存在a 变量,而 b 仍然引用旧对象
  • If we try to "clear" a though by setting a = {} 这不是清除它,它只是告诉 a 指向另一个 new 对象..

标签: javascript variables javascript-objects


【解决方案1】:

对您的两个问题的真正简短回答是,当您使一个变量与另一个变量相等时,复制第一个变量中的内容并存储在第二个变量中 - 没有链接两个变量之间。

但是,请继续阅读以了解更多详细信息以及为什么在某些情况下似乎存在链接...


与许多语言一样,JavaScript 将数据分为两大类:值类型和引用类型。 JavaScript 值类型是 its primitives

  • 字符串
  • 号码
  • 布尔值
  • 未定义
  • 符号

当您将这些类型中的任何一种分配给变量时,实际数据将存储在该变量中,如果您将一个变量设置为另一个变量,则原语的副本(不是链接)是制作并存储在新变量中:

var a = 10;  // Store the actual number 10 in the a variable
var b = a;   // Store a COPY of the actual number stored in a (10) in the b variable
a = 50;      // Change the actual data stored in a to 50 (no change to b here)
console.log(b);  // 10

当您使用 reference types 时,会发生一些不同的事情。将变量分配给引用类型意味着该变量仅保存对实际存储对象的内存位置的引用,而不是实际对象本身。所以,当你这样做时:

var a = {foo:"bar"};

a 实际上并不存储对象本身,它只存储可以找到对象的内存位置(即 0x3C41A)。

但是,就设置另一个变量等于第一个变量而言,它仍然可以像使用原语一样工作 - - 第一个变量中的副本是制作并赋予第二个变量。

这是一个例子:

// An object is instantiated in memory and a is given the address of it (for example 0x3C41A)
var a = {}; 
 
// The contents of a (the memory location of an object) is COPIED into b.
// Now, both a and b hold the same memory location of the object (0x3C41A)
var b = a;

// Regardless of whether a or b is used, the same underlying object
// will be affected:
a.foo = "test";
console.log(b.foo); // "test"

// If one of the variables takes on a new value, it won't change
// what the other variable holds:
a = "something else";
console.log(b);   // The object stored in memory location (0x3C41A)

因此,在您的第一次测试中,您只需通过两种方式访问​​一个对象,然后您将 a 持有的内容(对象的内存位置)更改为不同的对象,因此现在您只有一个通过b访问原始对象。


如果我们尝试通过设置 a = {} 来“清除”a,则对象 b 将保留 不变。我不明白为什么要以这种方式操作对象 产生与第一个示例不同的结果。

因为现在我们知道a = {} 没有清除对象。它只是将a 指向别的东西。

【讨论】:

【解决方案2】:

在您的第一种情况下:

var a = {
  fname: "Jon",
  lname: "Smith",
  age: 50
}

var b = a;
a = {}

b 保持不变,因为这是在后台发生的一系列事件:

  • 您使用数据在内存地址 0x1234 创建一个对象

    fname: "Jon", lname: "Smith", age: 50

  • 指向该内存块的指针存储在a

  • 然后将该指针复制到b

此时有两个对同一内存位的引用。更改该内存块中的任何内容都会影响对它的引用。

  • a = {} 不会清除内存块 0x1234,而是在另一个内存位置 (0x1235) 上创建一个新对象,并将指向该块的指针存储在 a 中。 0x1234 处的内存保持不变,因为b 仍然指向它。

简单变量和对象/指针之间的这种内存管理存在差异。字符串和数字的种类很简单,它们是“按值传递”的,而不是对象的“按引用传递”。

【讨论】:

    【解决方案3】:

    让我试着解释一下:

    1) 在您的示例中,ab 是对同一个对象的引用,而 a.fname(或 b.fname)是该对象的属性。所以在操作对象的属性时,它会在对象中发生变化,而引用不会受到影响,它们仍然指向同一个对象,对象本身已经发生了变化。另一方面,a = {} 只会替换对对象的引用,而不会影响对象本身或b 对它的引用。
    顺便说一句,您只是创建了对新空对象的新引用,这没有任何限制。

    2) 这些不是对象,因此您没有直接操作值的引用。这是因为对象和基元之间存在差异,如果您不习惯使用严格类型,这可能会让人感到困惑,尤其是在开始时。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-09-18
      • 1970-01-01
      • 1970-01-01
      • 2019-05-08
      • 2021-02-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多