做者:Chris Chujavascript
翻译:疯狂的技术宅前端
原文:alligator.io/js/deep-clo…java
未经容许严禁转载前端工程化
若是你打算用 JavaScript 进行编码,那么就须要了解对象的工做方式。对象是 JavaScript 最重要的元素之一,深刻理解了它会使你在编码时驾轻就熟。在克隆对象时,它并不像看起来那么简单。函数
当你不想改变原始对象时,就须要克隆对象。例如,若是你有一个接受对象并改变它的函数,可能不想改变其原始对象。工具
那么让咱们在 JavaScript 中建立一个对象:ui
let testObject = {
a: 1,
b: 2,
c: 3
};
复制代码
在上面的代码片断中,咱们初始化一个新对象并将其分配给变量 testObject
。如今对于大多数初学者来讲,他们会试着经过将 testObject
分配给新变量来建立这个对象的副本,以便在其代码中进行操做。很抱歉用这种方法行不通。编码
下面是一个代码片断,说明了为何不起做用。spa
let testObject = {
a: 1,
b: 2,
c: 3
};
// 为 testObject 建立一个副本
let testObjectCopy = testObject;
testObject.a = 9;
console.log(testObjectCopy.a);
// 这里 a = 9
复制代码
如上面的代码片断所示,建立新变量 testObjectCopy
实际上并不建立 testObject
的副本。相反它只是引用 testObject
。你对所谓的副本作的任何更改也将反映在原始对象中。prototype
循环遍历对象并将每一个属性复制到新对象也不起做用。
const copyObject = object => {
// 这是存储原始对象属性的对象
let copiedObj = {};
for (let key in object) {
// 这里将每一个属性从原始对象复制到复制对象
copiedObj[key] = object[key];
}
return copiedObj;
};
const testObject = {
a: 5,
b: 6,
c: {
d: 4
}
};
copyObject(testObject);
复制代码
上述方法存在如下几个问题:
for
循环和 Object.keys
中的属性。Object.prototype
方法,这不是复制对象时所需的方法。configurable
或 writable
设置为 false
,则复制对象中的属性描述符将会默认为 true
。对于仅存储基本类型(如数字和字符串)的简单对象,上述浅层复制方法将起做用。可是若是对象具备对其余嵌套对象的引用,则不会复制实际对象。你只会复制对其的引用。
对于深层复制,最简单的选择是使用可靠的外部库,如Lodash。
Lodash 提供两种不一样的功能,容许你进行浅拷贝和深拷贝,它们是 clone
和 clonedeep
。 Lodash 的优势在于你能够单独导入它的每一个函数,而无需将整个库放入你的项目中。这能够大大的减小依赖项的大小。
const clone = require('lodash/clone');
const cloneDeep = require('lodash/clonedeep');
// 你也能够这样作:
// const clone = require('lodash.clone');
// const cloneDeep = require('lodash.clonedeep');
// 取决于你本身的风格 :)
复制代码
如今就用 clone
和 clonedeep
函数作一些尝试:
const clone = require('lodash/clone');
const cloneDeep = require('lodash/clonedeep');
const externalObject = {
animal: 'Gator'
};
const originalObject = {
a: 1,
b: 'string',
c: false,
d: externalObject
};
const shallowClonedObject = clone(originalObject);
externalObject.animal = 'Crocodile';
console.log(originalObject);
console.log(shallowClonedObject);
// originalObject 和 shallowClonedObject 中的`animal`属性
// 是同时被改变的,由于它是一个浅的副本。
const deepClonedObject = clonedeep(originalObject);
externalObject.animal = 'Lizard';
console.log(originalObject);
console.log(deepClonedObject);
// 原始对象中的'animal'属性发生了变化,但对于
// deepClonedObject,它复制后仍然是'Crocodile'
// 对象是独立的而不是复制引用。
复制代码
在上面的代码中,咱们建立了一个名为 originalObject
的对象,它存储了 7 个属性,每一个属性都有不一样的值。属性 d
引用咱们的 externalObject
,它具备值为 Gator
的 animal
的属性。
当从 Lodash 执行 clone
函数时,它会建立一个对象的浅层副本,咱们将其分配给 shallowClonedObject
。在 externalObject
中为 animal
属性赋值一个新值将改变 originalObject
和 shallowClonedObject
,由于浅拷贝只能将引用复制到 externalObject
并它没有为本身创造一个全新的对象。
这就是 clonedeep
函数的用武之地。若是你对 deepClonedObject
执行相同的处理,那么 originalObject
的 d
属性是惟一要改变的属性。
🤓试一试,看看它如何帮助你编码!🚀