使用Object.assign对对象进行的更改会改变源对象

时间:2017-03-28 15:51:32

标签: javascript redux immutability

我在react-redux应用程序中有以下reducer代码:

    case 'TOGGLE_CLIENT_SELECTION':
        const id = action.payload.id;
        let newState = Object.assign({}, state);
        newState.list.forEach((client) => {
            if (client.id == id) client.selected = !client.selected;
        });
        console.log(state.list[0].selected + ' - ' + newState.list[0].selected)
        return newState;

如果我做对了 - Object.assign会创建全新的对象,但是console.log会显示" true - true" "假 - 假"。有什么想法,为什么它的行为像这样,我怎么能避免这种行为?

5 个答案:

答案 0 :(得分:3)

是的,但它并不是一本很深的副本。

新对象包含对旧列表的引用。

这是一个解决问题的伎俩(有更多"正确的"有些人可能会说的方式):

JSON.stringify原作。然后是JSON.parse那个字符串。新对象将是一个深层次的"复制(不确定这是否真的在技术上"深度复制")。它工作正常,除非您的子类型比标准的旧JSON可接受的东西更复杂。

答案 1 :(得分:2)

Object.assign将创建一个与另一个对象具有相同属性的新对象。其中一些属性是“按值”复制的,而其他属性则是“按引用”复制的。字符串,数字和布尔值是“按值”,而对象(包括日期)是“按引用”,这意味着它们指向同一个对象。

所以,例如,给定:

var otherState = { count: 10 };

var state = { text: "foo", otherState: otherState };

var newState = Object.assign({}, state);

newState.text = "bar";
newState.otherState.count = 9;

newState.text将为其分配一个全新的字符串,状态不会受到影响。但statenewState都引用otherState的同一个实例,因此当您将count更新为9时,state.otherState.countnewState.otherState.count都是影响。

使用Ojbect.state时,请使用以下规则:如果您到达第三个属性,则表示您现在处于“共享”状态:

newState.otherState.count = 0;
//  ^        ^        ^
//  |        |        |
//  1        2        3

答案 2 :(得分:0)

尝试一下:let newState = state.map(item => Object.assign({}, ...item)) 这将创建一个新对象,而无需引用旧对象state

答案 3 :(得分:0)

根据https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assignObject.assign修改了target对象,而不是创建一个新对象。

答案 4 :(得分:0)

您可以使用以下内容进行深层复制,然后将 Object.asign 与它一起使用:

const x = { id: "x" },
y = { id: "y" };
x.y = y;
y.x = x;
const cloneX = Object.fromEntries(Object.entries(x));

const cloneChangeX = Object.assign(cloneX, {z: {id: "z"}});

console.log('const x = ', x, '\nconst cloneX = ', cloneX, '\nconst cloneChangeX = ', cloneChangeX);

最后,您可以:

const cloneChangeX = Object.assign(
  Object.fromEntries(Object.entries(x)),
  { changekey: changevalue }
);