JS笔记之JS对象基础知识(二)
JS笔记之JS对象基础知识(二)
1 对象的引用和复制
对象和原始类型(数字字符串布尔类型等)的区别就是对象是通过引用 存储和复制的,而原始类型总是作为一个整体复制。
1.1 JS赋值时会发生什么?
首先原始类型进行赋值时,message 和 phrase 是两个独立的变量。之间没有什么直接的关系。
1 | let message = "Hello!"; |
而对象不是这样的,一个对象被赋值给某个变量,这个变量存储的并不是对象的本身,而是这个对象的内存的地址。
就像一把钥匙对应一个柜子,这把钥匙可以对该柜子打开并添加、取走里面的内容,此时又根据这把钥匙重新配了一个一个钥匙,而新配的这把钥匙也能够打开这个柜子。 这两把钥匙都可以对这个柜子修改。
1 | let user = { name: 'John' }; |
当一个对象变量被复制 —— 引用被复制,而该对象自身并没有被复制。
1.2 通过引用来比较
仅当两个对象为同一个对象时,两者才相等。
1 | let a = {}; |
而这里我们创建了两个空对象,看起来都是空的对象,但他们并不相等。
1 | let a = {}; |
1.3 克隆与合并
如果想要复制一个全新对象,可以循环遍历原有的对象,然后建立新的对象并进行创建。
还可以使用 Object.assign(dest, [src1, src2, src3...])
来创建。
1 | let user = { name: "John" }; |
如果被拷贝的属性已经存在,怎会覆盖掉原有的属性。
以上的情况都是建立在对象的属性都是原始类型的情况下,但是有些对象可能包含其他的对象,如果使用Object.assign()
不会对深层的对象进行拷贝,而是引用。
1 | let user = { |
为了解决这个问题,并让 user
和 clone
成为两个真正独立的对象,我们应该使用一个拷贝循环来检查 user[key]
的每个值,如果它是一个对象,那么也复制它的结构。这就是所谓的“深拷贝”。可以使用递归实现, 或者也可以使用现成的轮子, lodash 库的 _.cloneDeep(obj)。
1.4 总结
对象通过引用被赋值和拷贝。换句话说,一个变量存储的不是“对象的值”,而是一个对值的“引用”(内存地址)。因此,拷贝此类变量或将其作为函数参数传递时,所拷贝的是引用,而不是对象本身。
所有通过被拷贝的引用的操作(如添加、删除属性)都作用在同一个对象上。
为了创建“真正的拷贝”(一个克隆),我们可以使用 Object.assign
来做所谓的“浅拷贝”(嵌套对象被通过引用进行拷贝)或者使用“深拷贝”函数,例如 _.cloneDeep(obj)。