使用 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
returns 原始状态或实际原始状态的深层副本?
非常感谢您的帮助:)!
这很容易用
测试
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" }
这意味着它不会创建对象的深拷贝。
更新:
所以我产生了兴趣并大量测试了这个库,这是我的发现。
我上面写的代码片段只是库中的一个优化,returns 如果不做任何更改,则为旧状态。但是,如果您进行了一些更改,那么该库将开始按预期运行,并且以后无法进行更改。也就是说,
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 }
所以回到最初的问题,你能否通过不改变草稿中的任何内容来获得初始对象的深层副本。不,你不能,即使你这样做了(通过更改创建的 属性 可能只是为了愚弄 immer),生成的克隆对象将是不可变的并且没有真正帮助。
解决方案:
Immer 的产品仅在更新时提供新的深度克隆对象。
你可以创建你自己的 produce 函数,它的行为就像 immer 的 produce 一样,但每次使用 loadash
都会给出一个克隆的对象
import _ from 'lodash';
export default function produceClone(object, modifyfunction) {
let objectClone = _.cloneDeep(object);
if (!modifyfunction) return objectClone;
modifyfunction(objectClone);
return objectClone;
}
无论您是否修改对象,这都会每次都为您提供一个深度克隆(或深度复制)的对象。
我正在使用 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
returns 原始状态或实际原始状态的深层副本?
非常感谢您的帮助:)!
这很容易用
测试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" }
这意味着它不会创建对象的深拷贝。
更新:
所以我产生了兴趣并大量测试了这个库,这是我的发现。
我上面写的代码片段只是库中的一个优化,returns 如果不做任何更改,则为旧状态。但是,如果您进行了一些更改,那么该库将开始按预期运行,并且以后无法进行更改。也就是说,
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 }
所以回到最初的问题,你能否通过不改变草稿中的任何内容来获得初始对象的深层副本。不,你不能,即使你这样做了(通过更改创建的 属性 可能只是为了愚弄 immer),生成的克隆对象将是不可变的并且没有真正帮助。
解决方案: Immer 的产品仅在更新时提供新的深度克隆对象。 你可以创建你自己的 produce 函数,它的行为就像 immer 的 produce 一样,但每次使用 loadash
都会给出一个克隆的对象import _ from 'lodash';
export default function produceClone(object, modifyfunction) {
let objectClone = _.cloneDeep(object);
if (!modifyfunction) return objectClone;
modifyfunction(objectClone);
return objectClone;
}
无论您是否修改对象,这都会每次都为您提供一个深度克隆(或深度复制)的对象。