简体   繁体   English

避免 object 突变

[英]Avoiding object mutation

I am working with React and ES6.我正在使用 React 和 ES6。 So I arrivied to the following case: I have an state with an array of objects suppose a = [{id: 1, value: 1}, {id: 2, value: 2}] in the state of Object A , then I pass the list to Object B by props, Object B (in the constructor) copy the list to its own state and call a function which is using map function where I return b = [{id: 1, value: 1, text: 'foo'}, {id: 2, value: 2, text: 'foo'}] (added (text, value) to each object), so it though it was not mutating a in Object A but it was.所以我遇到了以下情况:我有一个 state 和一个对象数组假设a = [{id: 1, value: 1}, {id: 2, value: 2}]Object A的 state 中,然后我通过道具将列表传递给Object BObject B (在构造函数中)将列表复制到它自己的 state 并调用使用map function 的 function,其中我返回b = [{id: 1, value: 1, text: 'foo'}, {id: 2, value: 2, text: 'foo'}] (将(text, value)添加到每个对象),所以它虽然没有在Object A a发生变异,但确实发生了变异。

So I made some tests:所以我做了一些测试:

const a = [{id: 1, value: 1}, {id: 2, value: 2}] // suppose it is in object A

addText = (list) => {
    return list.map((item) => {item.text = "foo"; return item})
}

const b = addText(a) // suppose it is in object B

so under my assumption a !== b , but a was mutated by addText , so they were equal.所以在我的假设下a !== b ,但是aaddText变异了,所以它们是相等的。

In a large scale project programmers make mistakes (I did here?) how it is supposed to be handled this kind of situations to avoid mutating objects in this way?在大型项目中,程序员会犯错误(我在这里犯过错误?)应该如何处理这种情况以避免以这种方式改变对象? (The example tries to represet a as an state for Object A which is a component from React) (该示例尝试将a重新设置为state ,表示Object A是 React 的一个组件)

If your change to the object is really that shallow (at the top level of the object), you can use Object.assign({}, oldObj, newObj) , or if you have the Object spread proposal enabled in babel, { ...oldObj, newThing: 'thing' } 如果您对对象的更改非常浅(在对象的顶层),则可以使用Object.assign({}, oldObj, newObj) ,或者如果您在babel中启用了对象传播提议{ ...oldObj, newThing: 'thing' }

To enforce this on a team, you could use this ESLint plugin https://github.com/jhusain/eslint-plugin-immutable with the no-mutation rule enabled. 要在团队中强制执行此操作,您可以使用此ESLint插件https://github.com/jhusain/eslint-plugin-immutable并启用no-mutation规则。

By directly referring to item.text you are changing it.通过直接引用item.text你正在改变它。

Map iterates over an array. Map 遍历一个数组。 Since your array has objects, unlike primitive values, it doesn't duplicate them in the function scope. Instead, it passes by reference .由于您的数组具有对象,与原始值不同,它不会在 function scope 中复制它们。相反,它通过引用传递

The solution is to return new (duplicated) object values whilst iterating in the map function.解决方案是返回新的(重复的)object 值,同时迭代map function。

const a = [{id: 1, value: 1}, {id: 2, value: 2}]

addText = (list) => {
    return list.map((item) => {
        return {
            ...item,
            text: 'foo',
        };
    })
}

const b = addText(a)

You can simplify the syntax, and reduce indentation, by omitting the return statements as you are using arrow functions anyway.您可以通过省略return语句来简化语法并减少缩进,因为您无论如何都在使用箭头函数。

const a = [{id: 1, value: 1}, {id: 2, value: 2}]

addText = list => list.map(item => ({
    ...item,
    text: 'foo',
}));

const b = addText(a)

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

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