繁体   English   中英

使用 immer 在 JavaScript 中深度复制对象

[英]DeepCopy Object in JavaScript using immer

我正在使用immer来转换 react/redux 状态。 我也可以使用 immer 来深度复制一个对象而不转换它吗?

import produce, {nothing} from "immer"



const state = {
    hello: "world"
}

produce(state, draft => {})
produce(state, draft => undefined)
// Both return the original state: { hello: "world"}

这是来自官方的 immer README。 这是否意味着传递一个空函数来produce返回原始状态或实际上原始状态的深层副本?

非常感谢您的帮助 :)!

这很容易测试

import { produce } from 'immer'

const state = {
  hello: 'world',
}

const nextState = produce(state, draft => {})

nextState.hello = 'new world'
console.log(state, nextState)

哪个输出

Object { hello: "new world" }

Object { hello: "new world" }

这意味着它不会创建对象的深层副本。

更新:

所以我很感兴趣并经常测试了图书馆,这是我的发现。

我上面写的代码片段只是库中的一个优化,如果没有进行任何更改,它将返回旧状态。 但是,如果进行一些更改,那么库将按预期开始运行,之后的变异将无法实现。 那是,

const state = {
  hello: 'world',
}

const nextState = produce(state, draft => {
  draft.hello = 'new world';
})

nextState.hello = 'newer world';

console.log(state, nextState)

将导致错误: TypeError: "world" is read-only

这意味着你的newState是不可变的,你不能再对其执行突变。

我发现另一个相当有趣的事情是immer在使用class实例时失败了。 那是,

class Cls {
  prop = 10;
}

const instance = new Cls();

const obj = {
  r: instance,
};

const newObj = produce(obj, draft => {
  draft.r.prop = 15;
});

console.log(obj, newObj);

结果是

r: Object { prop: 15 }

r: Object { prop: 15 }

因此,要回到最初的问题,您是否可以通过更改草稿中的任何内容来获取初始Object的深层副本。 不,你不能,即使你做了(通过更改创建的属性只是为了愚弄immer),生成的克隆对象将是不可变的,并没有真正的帮助。

解决方案:Immer 的产品仅在更新时提供一个新的深度克隆对象。 您可以创建自己的生产功能,其行为与 immer 的生产功能类似,但每次使用 loadash 都会提供一个克隆对象

import _ from 'lodash';
export default function produceClone(object, modifyfunction) {
    let objectClone = _.cloneDeep(object);
    if (!modifyfunction) return objectClone;
    modifyfunction(objectClone);
    return objectClone;
    }

无论您是否修改对象,这每次都会为您提供一个 deepCloned(或深度复制)对象。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM