本节书摘来自异步社区《JavaScript启示录》一书中的第1章,第1.13节,作者:【美】Cody Lindley著,更多章节内容可以访问云栖社区“异步社区”公众号查看
1.13 如何存储或复制复杂值
复杂值是通过引用进行存储和操作的,理解这一点相当重要。创建一个包含复杂对象的变量时,其值是内存中的一个引用地址。引用一个复杂对象时,使用它的名称(即变量或对象属性)通过内存中的引用地址获取该对象值。当考虑试图复制一个复杂值时会发生什么事的时候,这就非常重要了。下面创建一个对象,并将它保存在变量myObject中,然后将myObject中的这个值复制到变量copyOfMyObject中。实际上,这并不是复制对象,更像是复制对象的地址。
<!DOCTYPE html><html lang="en"><body><script>
var myObject = {};
var copyOfMyObject = myObject; //没有复制值,而是复制了引用
myObject.foo = 'bar'; // 操作myObject中的值
/* 现在如果输出myObject和copyOfMyObject,则均会输出foo属性,因为它们引用的是同一个对象*/
console.log(myObject, copyOfMyObject); /* 输出 'Object { foo="bar"}
Object { foo="bar"}' */
</script></body></html>
我们必须认识到的是,与复制值的原始值不同,对象(也称为复杂值)是通过引用进行存储的。因此,复制的是引用(也称为地址),而不是实际的值。这意味着根本就没有复制对象。就像我说过的,复制的是内存堆栈中对象的地址或引用。在代码示例中,myObject和copyOfMyObject都指向存储于内存中的同一个对象。
这里的重点是,当更改复杂值时,所有引用相同地址的变量的值都会被修改,因为复杂值是通过引用进行存储的。在上述代码示例中,更新myObject和copyOfMyObject中任何一个变量中的值,两者都会被更改。
注意
- 使用new关键字创建String()、Number()和Boolean()值时,或者这些值在幕后被转换成复杂对象时,值依然是按照值进行存储/复制的。因此,即使原始值可以被看做是复杂值,它们也不具备通过引用进行复制的特性。
- 若要真正地复制一个对象,必须要从旧的对象中提取值,并将提取的值注入新对象。