两个具有相同属性的对象。删除一个对象的属性有什么影响?

时间:2017-12-19 07:26:20

标签: javascript

我对这两种情况感到困惑:

第一个:

let a: object = {'name': 'gavin'};
let b: object = {};
b['name'] = a['name']; // at this time. a and b are both {'name': 'gavin'};
delete a['name']; // now a is {} and b is {'name': 'gavin'}

第二个:

let a: object = {'tag': {'name': 'gavin'}};
let b: object = {};
b['tag'] = a['tag']; // at this time. a and b are both {'tag': {'name': 'gavin'}};
delete a['tag']['name']; // now a and b are both {'tag': {}}

在第二种情况下,如果我delete a['tag'],则a为{},b为{'tag': {'name': 'gavin'}}。正如我所料,如果我删除a['tag'],则b将为空,如果我删除a['tag']['name'],则b不会受到影响。为什么会出现这样的结果?

英语不是我的母语,如果我拼写错误,请不要犹豫,让我知道。

1 个答案:

答案 0 :(得分:4)

在第一个示例中,您要分配字符串b['name'] = a['name']。字符串在javascript中通过值传递,因此有效地在内存中创建该字符串的新副本。 a['name']就其引用的实际内存位置而言不等于b['name']

您可以将此视为拥有两个字符串副本。删除字符串时,删除一个副本,但不删除另一个副本。

在第二个示例中,您正在分配对象b['tag'] = a['tag']。对象通过javascript中的引用传递,这意味着您不是要创建对象的新副本,而是将同一对象分配给b['tag']。因此a['name']b['name']是同一个对象。

您可以将此视为拥有一个对象副本,其中a['tag']b['tag']都使用该副本。从该单个副本中删除名称属性时,它不会显示在a['tag']b['tag']中,因为它们都使用同一个对象。

这个问题的答案可能有助于您理解更好的价值与对象参考https://stackoverflow.com/a/37290849/845704

修改

或许可以将它放在透视图中,让我们将您的示例与其他变量一起使用。请记住,这与您的示例的数据结构没有什么不同,除了它是更多的代码行。

let tag_obj = {'name': 'gavin'};
let a = { 'tag': tag_obj };
let b = {};
b['tag'] = a['tag'];

// a and b both now equal { tag: { name: 'gavin'} }

console.log(a.tag === tag_object) // True, it references tag object
console.log(b.tag === tag_object) // Also true, as it references the same object.

delete a.tag.name; 

现在,如果您delete a.tag,则要从a对象中删除属性。哪个不应该影响其他任何因素,因为a不等于其他任何东西。但是,当您delete a.tag.name时,您要删除tag对象中的属性,我们在上面的示例中将其称为tag_object。由于a.tagb.tag都引用tag_object,现在它们都会显示没有名称属性。

没有本地“运算符”来创建对象的附加副本,但是有一些常用的方法。第一个是Object.assign,它将一个对象的属性分配给另一个对象

let j = {'tag': {'name': 'james'}};
let k = j
console.log(k === j) // Will log true, they are the same object

let a = {'tag': {'name': 'gavin'}};
let b = Object.assign({}, a);
console.log(a === b) // Will log false, a new object has been created.

现在两个对象看起来都一样。不幸的是,Object.assign创建了所谓的浅拷贝。因此,对象本身是不同的,但是对象内的任何引用都将被共享

let a = {'tag': {'name': 'gavin'}};
let b = Object.assign({}, a);
console.log(a.tag === b.tag) // Will log true, they share the same tag object

周围有一些实用程序库可以为您创建对象的深层副本。您也可以通过遍历整个对象树来递归地执行此操作。

但是,创建对象的深层副本的一种常见且相当快速的方法是使用JSON。

let j = {'tag': {'name': 'james'}};
let k = JSON.parse(JSON.stringify(j));
console.log(j === k); // Will log false, a new object has been created.
console.log(j.tag === k.tag); // Will log false, a new object has been created.

此机制首先使用JSON.stringify生成一个新字符串,此时它不再与源对象绑定。然后,它使用JSON.parse从该字符串生成一个全新的对象。

注意

如果使用JSON方法,则不会保留函数,因为函数无法以任何标准JSON格式进行序列化。