如何正确创建一个新对象,该对象是另一个对象的副本?

时间:2019-04-19 02:11:34

标签: javascript

我记得能够像这样的传播算子克隆对象:

let obj1 = {
  key: 'value',
  key2: 'value2'  
}

let obj2 = { ...obj1 }

但是现在我意识到这是行不通的,因为我试图更改obj2的值,并且还更改了obj1中的值。

如果我这样做了:

obj2.key2 = 'test'

它也会将obj1.key2也更改为“测试”。

为什么会这样?

我也尝试这样做:

let obj2 = Object.assign({}, obj1)

但是我面临同样的问题。

谢谢

let obj1 = {
  key1: 'value1',
  key2: 'value2'
}

let obj2 = { ...obj1 }

obj2.key2 = 'changed key2 value'

console.log( obj1.key2 == obj2.key2 )


3 个答案:

答案 0 :(得分:0)

首先,您只有一半的权利。您正在执行的操作称为“浅克隆”,它将对象的所有属性复制到另一个对象。现在,如果这些属性是基元(数字/字符串),则可以安全地在一个对象上更改它们,而无需更改其他对象。但是对于对象或数组,实际上是在复制它们的引用。因此,如果testKey是对象,那么当您执行obj1.testKey时,您所指的对象与您执行obj2.testKey时所指的对象相同。

为了进行所谓的“深度克隆”以免发生这种情况,您有2个选择。

手动将它们散布在这些对象上,

let obj1 = {
    key: {
        value: 1
    },
    key2: 2
}

let obj2 = {
    ...obj2,
    key: {
        ...obj1.key
    }
}

这可能真的很累,特别是在大型结构或更高级别的嵌套中。我推荐的第二个选项是使用lodash cloneDeephttps://lodash.com/docs/4.17.11#cloneDeep

答案 1 :(得分:0)

Object.assign()方法用于将所有可枚举的自身属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。


[global]
  checkNewVersion = false
  sendAnonymousUsage = false

debug = true
logLevel = "DEBUG"

InsecureSkipVerify = true

defaultEntryPoints = ["http", "https"]

#[web]
#address = ":8080"

[api]
entryPoint = "traefik"
dashboard = true
address = ":8080"

[entryPoints]
  [entryPoints.http]
  address = ":80"
    #[entryPoints.http.redirect]
    entryPoint = "https"

  [entryPoints.https]
  address = ":443"
    [entryPoints.https.tls]

[file]
watch = true

[backends]
  [backends.backend1]
   [backends.backend1.servers]
    [backends.backend1.servers.server0]
    url = "http://127.0.0.1:8000"

[frontends]
  [frontends.frontend1]
   entrypoints = ["http","https"]
   backend = "backend1"
   passHostHeader = true
   #passTLSCert = true

   [frontends.frontend1.routes]
    [frontends.frontend1.routes.route0]
     rule = "Host:MYDOMAIN"

      # rule = "PathPrefix: /app"
      # rule = "Host: localhost; PathPrefix: /app"

   [frontends.frontend1.redirect]
      entryPoint = "https"
      regex = "^http://localhost/(.*)"
      replacement = "http://MYDOMAIN/$1"
      permanent = true

[docker]
endpoint = "unix:///var/run/docker.sock"
domain = "MYDOMAIN"
watch = true
exposedbydefault = false


[acme]
email = "EMAIL"
storage = "acme.json"
#caServer = "https://acme-staging-v02.api.letsencrypt.org/directory"
caServer = "https://acme-v02.api.letsencrypt.org/directory"
entryPoint = "https"

[acme.httpChallenge]
entryPoint = "http"

[[acme.domains]]
  main = "MYDOMAIN"


syntax:
    Object.assign(target, ...sources)
    target: The target object.
    sources: The source object(s).
    Return value: The target object.

let a = {}
let b = {
  key: 'value',
  key2: 'value2'  
}

Object.assign(a, b)
a.key2 = '123'
console.log(a.key2 == b.key2) // false
// a: {key: "value", key2: "123"}
// b: {key: "value", key2: "value2"}

答案 2 :(得分:-1)

原因是因为assign()仅创建对原始对象的引用(指针)。因此,如果更改参考对象,则将更改原始对象。要完全复制对象,通常我将对象转换为JSON,然后再返回到新对象:

let obj1 = {
  key: 'value',
  key2: 'value2'
}

console.log("Ojbect 1, key:" + obj1.key);

let obj2 = JSON.parse(JSON.stringify(obj1));

obj2.key = "new_value";

console.log("Object 1, key:" + obj1.key);
console.log("Object 2, key:" + obj2.key);