【问题标题】:Why javascript object value is changed? [duplicate]为什么javascript对象的值会改变? [复制]
【发布时间】:2020-01-11 02:34:27
【问题描述】:

谁能解释一下为什么输出值改为“20, 2”而不是原来的“1, 2”?

<!DOCTYPE html>
<html>
<body>
  <p id="demo"></p>
  <p id="demo1"></p>
  <script>
    var x = {
      a: 1,
      b: 2
    };
    var y = x;
    y.a = 20;
    document.getElementById("demo").innerHTML = x.a;
    document.getElementById("demo1").innerHTML = x.b;
  </script>
</body>
</html>

【问题讨论】:

  • JS 通过引用传递对象,有一些与此相关的深入问题:stackoverflow.com/questions/16880418/…
  • 由于您似乎是 JavaScript 新手,我强烈建议 not 使用 var,因为这被认为是不好的做法。您应该使用letconst
  • @Seblor 我认为在前端 JS 中使用 var 并没有错,事实上,如果您的目标是获得广泛的浏览器支持,我们仍然(不幸的是)必须避免使用 let/const 的边界。
  • @DBS 虽然我理解你的意思,但我真的认为var 的使用和浏览器支持应该留给转译器(如 Babel)。如果人们继续使用var,他们以后将很难改变。此外,使用较新的 ECMAScript 版本通常会提高代码的可读性。

标签: javascript object


【解决方案1】:

因为它是相同的reference(存储对象的内存位置的地址相同)现在 x 和 y 都是相同的引用,因此更改一个将更改存储的值,现在因为它们是相同的引用,它们将输出相同的对象值。

我会添加一些额外的东西来使这个答案更有效率。

浅拷贝

浅拷贝是对象的按位拷贝。创建了一个新对象 它具有原始对象中值的精确副本。如果有任何一个 对象的字段是对其他对象的引用,只是 引用地址被复制,即只有内存地址是 复制。

例子

let x={"a":1,"b":2};
let y=x;  //It makes a copy of the reference to x into y

因此,x 和 y 的地址将相同,即它们将指向相同的内存位置。 所以如果你这样做

y.a=9;

现在当你在屏幕上打印 y 时

console.log(y) // it prints {"a":9,"b":2};

但有趣的事实是,当您打印 x 时

console.log(x)  // it also prints {"a":9,"b":2};

那么现在如何改变这种情况??解决方案是深拷贝

深拷贝

深拷贝复制所有字段并动态复制 字段指向的分配内存。当一个深拷贝发生时 对象与它所引用的对象一起被复制。

在雷曼术语中,您创建一个变量 y 为其分配不同的内存位置,复制 x 的所有成员,将复制的成员分配给 y

最简单的方法是通过stringifying对象

let y=JSON.parse(JSON.stringify(x))

现在如果我们这样做

y.a=9

并打印 y

console.log(y) // it prints {"a":9,"b":2};

如果我们打印 x

console.log(x) //  it prints {"a":1,"b":2};

/// shallow copy

let x = {
  "a": 1,
  "b": 2
};
let y = x;
y.a = 9;
console.log(y);
console.log(x);


// Deep Copy

let z = {
  "a": 1,
  "b": 2
};
let t = JSON.parse(JSON.stringify(z));
t.a = 9;
console.log("z:", z);
console.log("t:", t);
当我们有嵌套对象时,这个场景变得更有趣

let c = {
  "a": {
    "A": 1
  },
  "b": {
    "B": 2
  }
};
let t = Object.assign({}, c); // It is also shallow copying
t.a.A = "7"; // since a is a nested object so again reference is passed
console.log(c);
console.log(t)
console.log("Second Scenario-------------------")


let d = {
  "a": {
    "A": 1
  },
  "b": {
    "B": 2
  }
};
let k = JSON.parse(JSON.stringify(d));
k.a.A = 88
console.log(d)
console.log(k)

【讨论】:

    【解决方案2】:

    您将y 指向x 的引用,它本身指向对象{a:1,b:2}

    所以在记忆中是:

    x --> {a:1,b:2}
    

    你做y = x之后就变成了:

    y --> x --> {a:1,b:2}
    

    或者简单地说:

    x --> {a:20,b:2}
             ^
             |
    y -------
    

    现在当您执行y.a = 20 时,由于yx 都指向同一个对象,当对象的属性通过引用xy 中的任何一个更改时,更改将被反映在这两个参考文献中:

    y --> {a:20,b:2}
            ^
            |
    x -------
    

    这就是为什么当你得到x.a时你得到20,2

    【讨论】:

      【解决方案3】:

      那是因为y & x 都指向同一个内存位置。如果你想要一个单独的副本,然后深复制对象。 JSON.parse & JSON.stringify

      var x = {
        a: 1,
        b: 2
      };
      var y = JSON.parse(JSON.stringify(x));
      y.a = 20;
      document.getElementById("demo").innerHTML = x.a;
      document.getElementById("demo1").innerHTML = x.b;
      <p id="demo"></p>
      <p id="demo1"></p>

      【讨论】:

        【解决方案4】:
        var y=x
        

        在上面的行中y 传递了x 的引用而不是整个对象x。对对象所做的任何更改都将反映在包含对象引用的所有变量中。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-04-18
          • 2015-03-16
          • 1970-01-01
          • 1970-01-01
          • 2018-07-28
          • 1970-01-01
          • 2021-08-13
          相关资源
          最近更新 更多