我对这两种情况感到困惑:
第一个:
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不会受到影响。为什么会出现这样的结果?
英语不是我的母语,如果我拼写错误,请不要犹豫,让我知道。
答案 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.tag
和b.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格式进行序列化。