不可变地删除对象中的属性

时间:2015-12-21 17:18:27

标签: javascript immutability redux

我正在使用Redux。在我的reducer中,我尝试从像这样的对象中删除属性:

userlabel.Text = AuthUser;

我希望有这样的东西而不必改变原始状态:

const state = {
    a: '1',
    b: '2',
    c: {
       x: '42',
       y: '43'
    },
}

我试过了:

const newState = {
    a: '1',
    b: '2',
    c: {
       x: '42',
    },
}

但由于某些原因,它会从两个州删除该属性。

可以帮我这么做吗?

16 个答案:

答案 0 :(得分:141)

如何使用destructuring assignment语法?



const original = {
  foo: 'bar',
  stack: 'overflow',
};

// If the name of the property to remove is constant
const { stack, ...withoutFirst } = original;
console.log(withoutFirst); // Will be { "foo": "bar" }

// If the name of the property to remove is from a variable
const key = 'stack'
const { [key]: value, ...withoutSecond } = original;
console.log(withoutSecond); // Will be { "foo": "bar" }

// To do a deep removal with property names from variables
const deep = {
  foo: 'bar',
  c: {
   x: 1,
   y: 2
  }
};

const parentKey = 'c';
const childKey = 'y';
// Remove the 'c' element from original
const { [parentKey]: parentValue, ...noChild } = deep;
// Remove the 'y' from the 'c' element
const { [childKey]: removedValue, ...childWithout } = parentValue;
// Merge back together
const withoutThird = { ...noChild, [parentKey]: childWithout };
console.log(withoutThird); // Will be { "foo": "bar", "c": { "x": 1 } }




答案 1 :(得分:44)

我发现像filtermapreduce这样的ES5数组方法很有用,因为它们总是返回新的数组或对象。在这种情况下,我会使用Object.keys迭代对象,并使用Array#reduce将其转换回对象。

return Object.assign({}, state, {
    c: Object.keys(state.c).reduce((result, key) => {
        if (key !== 'y') {
            result[key] = state.c[key];
        }
        return result;
    }, {})
});

答案 2 :(得分:34)

您可以使用lodash库中的_.omit(object, [paths])

路径可以嵌套,例如:_.omit(object, ['key1.key2.key3'])

答案 3 :(得分:23)

只需使用ES6对象解构功能



const state = {
    c: {
       x: '42',
       y: '43'
    },
}

const { c: { y, ...c } } = state // generates a new 'c' without 'y'

console.log({...state, c }) // put the new c on a new state




答案 4 :(得分:22)

那是因为您正在将state.c的值复制到另一个对象。该值是指向另一个javascript对象的指针。所以,这两个指针都指向同一个对象。

试试这个:

let newState = Object.assign({}, state);
console.log(newState == state); // false
console.log(newState.c == state.c); // true
newState.c = Object.assign({}, state.c);
console.log(newState.c == state.c); // now it is false
delete newState.c.y;

您还可以对该对象进行深层复制。请参阅this question,您将找到最适合您的方式。

答案 5 :(得分:16)

这个怎么样:

function removeByKey (myObj, deleteKey) {
  return Object.keys(myObj)
    .filter(key => key !== deleteKey)
    .reduce((result, current) => {
      result[current] = myObj[current];
      return result;
  }, {});
}

它过滤应删除的键,然后从剩余的键和初始对象构建一个新对象。这个想法是从Tyler McGinnes真棒反应计划中偷来的。

JSBin

答案 6 :(得分:10)

function dissoc(key, obj) {
  let copy = Object.assign({}, obj)
  delete copy[key]
  return copy
}

此外,如果要查找函数式编程工具包,请查看Ramda

答案 7 :(得分:8)

在您的情况下,您可以使用Immutability helper取消设置属性:

import update from 'immutability-helper';

const updatedState = update(state, {
  c: {
    $unset: ['y']
  }
});    

答案 8 :(得分:5)

使用Immutable.js

很容易
const newState = state.deleteIn(['c', 'y']);

description of deleteIn()

答案 9 :(得分:2)

您遇到的问题是您没有深入克隆您的初始状态。所以你的副本很浅。

您可以使用点差运算符

  const newState = { ...state, c: { ...state.c } };
  delete newState.c.y

或遵循相同的代码

let newState = Object.assign({}, state, { c: Object.assign({}, state.c) });
delete newState.c.y

答案 10 :(得分:1)

我通常使用

Object.assign({}, existingState, {propToRemove: undefined})

我意识到这实际上并没有删除该属性,但几乎所有目的 1 它的功能相同。这种语法比我认为非常好的替代方案简单得多。

1 如果您使用hasOwnProperty(),则需要使用更复杂的解决方案。

答案 11 :(得分:1)

我使用这种模式

const newState = Object.assign({}, state);
      delete newState.show;
      return newState;

但在书中我看到了另一种模式

return Object.assign({}, state, { name: undefined } )

答案 12 :(得分:0)

As hinted in some of the answers already, it's because you are trying to modify a nested state ie. one level deeper. A canonical solution would be to add a reducer on the x state level:

const state = {
    a: '1',
    b: '2',
    c: {
       x: '42',
       y: '43'
    },
}

Deeper level reducer

let newDeepState = Object.assign({}, state.c);
delete newDeepState.y;

Original level reducer

let newState = Object.assign({}, state, {c: newDeepState});

答案 13 :(得分:0)

实用程序;))

const removeObjectField = (obj, field) => {

    // delete filter[selectName]; -> this mutates.
    const { [field]: remove, ...rest } = obj;

    return rest;
}

操作类型

const MY_Y_REMOVE = 'MY_Y_REMOVE';

动作创建者

const myYRemoveAction = (c, y) => {

    const result = removeObjectField(c, y);

        return dispatch =>
            dispatch({
                type: MY_Y_REMOVE,
                payload: result
            })
    }

<强>减速器

export default (state ={}, action) => {
  switch (action.type) {
    case myActions.MY_Y_REMOVE || :
      return { ...state, c: action.payload };
    default:
      return state;
  }
};

答案 14 :(得分:0)

从2019年开始,另一种选择是使用Object.fromEntries方法。已经到了阶段4。

const newC = Object.fromEntries(
    Object.entries(state.c).filter(([key]) => key != 'y')
)
const newState = {...state, c: newC}

关于它的好处是它可以很好地处理整数键。

答案 15 :(得分:0)

这里有一个简单的1-liner,您可以使用它来部分应用要删除的道具。这样可以轻松传递到Array.map

const removeProp = prop => ({ [prop]: _, ...rest }) => ({ ...rest })

现在您可以像这样使用它:

const newArr = oldArr.map(removeProp('deleteMe'))