javascript深度图_在JavaScript中深度克隆对象(及其工作方式)

javascript深度图

If you plan on coding with JavaScript, you need to understand how objects work. They’re one of the most important elements of JavaScript and a deep (pun intended) understanding of objects will always be handy. Especially when cloning an object, it isn’t as simple as it might seem.

如果计划使用JavaScript进行编码,则需要了解对象的工作方式。 它们是JavaScript的最重要元素之一,对对象的深刻理解(双关语意)总是很方便的。 特别是在克隆对象时,它并不像看起来那样简单。

You need to clone an object if you don’t want to mutate your original object. For example, if you have a function that takes in an object and alters it, you probably don’t want to mutate your original object.

如果不想突变原始对象,则需要克隆一个对象。 例如,如果您有一个接受一个对象并对其进行更改的函数,则可能不想更改原始对象。



So let’s create an object in JavaScript:

因此,让我们在JavaScript中创建一个对象:

let testObject = {
  a: 1,
  b: 2,
  c: 3
};

In the above code snippet, we initialize a new object and assign it to the variable testObject. Now for most beginners, they’ll try to create a copy of this object to manipulate in their code by assigning the testObject to a new variable. I’ve personally been guilty of this for longer than I care to admit.

在上面的代码片段中,我们初始化了一个新对象,并将其分配给变量testObject 。 现在,对于大多数初学者而言,他们将尝试通过将testObject分配给新变量来创建此对象的副本以在其代码中进行操作。 我个人对此感到内than的时间超过了我愿意承认的时间。

Below is a code snippet that shows why that won’t work.

下面是一个代码片段,显示了为什么不起作用。

let testObject = {
  a: 1,
  b: 2,
  c: 3
};

// Creating a new variable that 'copies' our testObject
let testObjectCopy = testObject;

testObject.a = 9;
console.log(testObjectCopy.a);
// This returns a = 9

As shown in the code snippet above, creating the new variable testObjectCopy doesn’t actually create a copy of testObject. Instead, it’s simply referencing the testObject. Any changes you make to the assumed copy will reflect in the original object as well.

如上面的代码片段所示,创建新变量testObjectCopy实际上并不创建testObject的副本。 相反,它只是引用testObject 。 您对假定副本所做的任何更改也将反映在原始对象中。

Looping through the object and copying each property to a new object wouldn’t work either.

遍历对象并将每个属性复制到一个新对象也不起作用。

const copyObject = object => {
  // This is the object that will store the original object's properties
  let copiedObj = {};

  for (let key in object) {
    // This copies each property from the original object to the copy object
    copiedObj[key] = object[key];
  }

  return copiedObj;
};

const testObject = {
  a: 5,
  b: 6,
  c: {
    d: 4
  }
};

copyObject(testObject);

There are several issues with the approach above:

上面的方法存在几个问题:

  • Point 1. A loop that copies each property to a new object would only copy enumerable properties on the object. Enumerable properties are properties that will show up in for loops and Object.keys.

    点1 。 将每个属性复制到一个新对象的循环只会在该对象上复制可枚举的属性。 可枚举的属性是将显示在for循环和Object.keys中的属性。

  • Point 2. The copied object has a new Object.prototype method, which is not what you want when you copy an object.

    点2 。 复制的对象具有一个新的Object.prototype方法,该方法不是复制对象时所需的。

  • Point 3. If your object has a property that is an object, your copied object will actually refer to the original instead of creating an actual copy. This means that if you change that nested object in the copied object, the original gets changed as well.

    点3 。 如果您的对象具有作为对象的属性,则复制的对象实际上将引用原始对象,而不是创建实际的副本。 这意味着,如果在复制的对象中更改该嵌套对象,原始对象也将更改。

  • Point 4. Any property descriptors are not copied. If you set things like configurable or writable to false, the property descriptors in the copied object will default to true.

    点4 。 不复制任何属性描述符。 如果将诸如configurablewritable类的内容设置为false ,则复制对象中的属性描述符将默认为true



那么,如何正确地复制对象? (So How Can I Copy an Object the Right Way?)

For simple objects that only stores primitive types like numbers and strings, shallow copying methods like the one above will work. However, if your object features references to other nested objects, the actual object won’t be copied. You would only be copying the reference.

对于仅存储数字和字符串等原始类型的简单对象,可以使用上述一种浅复制方法。 但是,如果您的对象具有对其他嵌套对象的引用,则不会复制实际对象。 您只会复制参考 。

For a deep copy, the easiest option is to use reliable external libraries like Lodash.

对于深层副本,最简单的选择是使用可靠的外部库,例如Lodash

使用Lodash克隆和Clonedeep (Using Lodash Clone And Clonedeep)

Lodash comes with two different functions that allow you to do shallow copies and deep copies. These are clone and clonedeep. The great thing about Lodash is that you can import each function individually, without requiring the entire library into your project. This can wildly reduce the size of your dependencies.

Lodash带有两个不同的功能,可让您进行浅拷贝和深拷贝。 这些是cloneclonedeep 。 Lodash的妙处在于,您可以单独导入每个函数,而无需将整个库导入到项目中。 这可以大大减少依赖项的大小。

const clone = require('lodash/clone'); 
const cloneDeep = require('lodash/clonedeep');

// You could also do:
// const clone = require('lodash.clone');
// const cloneDeep = require('lodash.clonedeep');
// Depends on your style :)

Now to use the clone and clonedeep function, here’s some code to try out:

现在要使用cloneclonedeep函数,请尝试以下代码:

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);
// The `animal` property in both the originalObject and shallowClonedObject 
// are both changed this way since it's a shallow copy.

const deepClonedObject = clonedeep(originalObject);

externalObject.animal = 'Lizard';

console.log(originalObject);
console.log(deepClonedObject);

// The 'animal' property in the originalObject changes, but for the
// deepClonedObject, it remains as 'Crocodile' since it copied
// the entire object separately instead of copying the reference.

In the above code, we create our object called originalObject, which stores 7 properties with different values in each. The property d references our externalObject which has the property of animal and a value of 'Gator'.

在上面的代码中,我们创建了一个名为originalObject的对象,该对象存储7个属性,每个属性具有不同的值。 属性d引用我们的externalObject ,该对象具有animal属性并且值为'Gator'

When we do the clone function from Lodash, it creates a shallow copy of the object, which we assign to shallowClonedObject. Assigning the animal property in our externalObject a new value will change both the originalObject and the shallowClonedObject because the shallow clone was only able to copy the reference to the externalObject. It didn’t create a brand new object for itself.

当我们从Lodash执行clone函数时,它将创建对象的浅表副本,并将其分配给shallowClonedObject 。 在我们的externalObjectanimal属性分配一个新值将同时更改originalObjectshallowClonedObject因为浅表克隆只能将引用复制到externalObject 。 它并没有为自己创建一个全新的对象。

This is where the clonedeep function comes in. If you do the same process above for the deepClonedObject, the originalObject’s d property is the only one to change.

这就是clonedeep功能用武之地,如果你做上面的相同过程deepClonedObject中, originalObjectd属性是唯一一个变化。

Try it out and see how this can help your code!

尝试一下,看看它如何帮助您的代码!

翻译自: https://www.digitalocean.com/community/tutorials/js-deep-cloning-javascript-objects

javascript深度图

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值