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

Vin*_*ing 119 javascript immutability redux

我正在使用Redux.在我的reducer中,我试图从像这样的对象中删除一个属性:

const state = {
    a: '1',
    b: '2',
    c: {
       x: '42',
       y: '43'
    },
}
Run Code Online (Sandbox Code Playgroud)

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

const newState = {
    a: '1',
    b: '2',
    c: {
       x: '42',
    },
}
Run Code Online (Sandbox Code Playgroud)

我试过了:

let newState = Object.assign({}, state);
delete newState.c.y
Run Code Online (Sandbox Code Playgroud)

但由于某些原因,它会删除两个州的财产.

可以帮我这么做吗?

mad*_*vid 168

如何使用解构赋值语法?

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 } }
Run Code Online (Sandbox Code Playgroud)

  • 太好了!这是一个es6辅助函数,它与`const deleteProperty =({[key]:_,... newObj},key)=> newObj;`.用法:`deleteProperty({a:1,b:2},"a");`给`{b:2}` (11认同)
  • 很棒,没有额外的库,可以使用es6并且非常简单。 (2认同)

Dav*_*lsh 45

我觉得ES5阵列的方法,如filter,mapreduce有用的,因为他们总是返回新的数组或对象.在这种情况下,我将使用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;
    }, {})
});
Run Code Online (Sandbox Code Playgroud)

  • ES6相当于获取了一个`myObject`的副本,其中删除了键'myKey`:`Object.keys(myObject).reduce((acc,cur)=> cur === myKey?acc:{... acc,[cur ]:myObject [cur]},{})` (2认同)

小智 35

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

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

  • 不幸的是,`_.omit`无法删除深层属性(OP要求的是什么).为此目的,有[`omit-deep-lodash`](https://www.npmjs.com/package/omit-deep-lodash)模块. (3认同)
  • 离开@AlexM 所说的。我发现它对我们来自 lodash 的 ```_.cloneDeep(obj)``` 很有用,而且可能更合适。这很容易复制对象,然后你可以简单地使用 js ```delete obj.[key]``` 来删除键。 (2认同)

Ram*_*ogo 24

只需使用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
Run Code Online (Sandbox Code Playgroud)

  • 注意:这对于由整数键入的对象不起作用 (8认同)
  • `const {y,... c} = state.c`可能比在左侧有两个`c`更清晰一些. (6认同)
  • 从下面的答案中,如果你需要引用要删除的变量名:`const name ='c'`那么你可以做`const {[name]:deletedValue,... newState} = state`然后返回`newState `在你的减速机里.这是用于顶级密钥删除 (2认同)

Aᴍɪ*_*ᴍɪʀ 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;
Run Code Online (Sandbox Code Playgroud)

您还可以对该对象执行深层复制.看到这个问题,你会发现什么是最适合你的.

  • 这是一个很好的答案!`state.c`是一个引用,并且正在复制引用.Redux需要一个规范化的状态形状,这意味着在嵌套状态时使用id而不是引用.查看redux文档:http://redux.js.org/docs/recipes/reducers/NormalizingStateShape.html (2认同)

Seb*_*ebK 17

这个怎么样:

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

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

JSBin


Dom*_*kis 10

function dissoc(key, obj) {
  let copy = Object.assign({}, obj)
  delete copy[key]
  return copy
}
Run Code Online (Sandbox Code Playgroud)

此外,如果要寻找功能性编程工具包,请查看Ramda.


Jav*_*r P 9

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

import update from 'immutability-helper';

const updatedState = update(state, {
  c: {
    $unset: ['y']
  }
});    
Run Code Online (Sandbox Code Playgroud)


jia*_*ian 9

截至 2019 年,另一种选择是使用该Object.fromEntries方法。它已经达到了第 4 阶段。

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

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


Bre*_*ung 6

您可以使用以下简单的 1-liner 来部分应用要移除的道具。这使得很容易传递到Array.map.

const removeProp = prop => ({ [prop]: _, ...rest }) => ({ ...rest })
Run Code Online (Sandbox Code Playgroud)

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

const newArr = oldArr.map(removeProp('deleteMe'))
Run Code Online (Sandbox Code Playgroud)


quo*_*Bro 5

使用Immutable.js很容易:

const newState = state.deleteIn(['c', 'y']);
Run Code Online (Sandbox Code Playgroud)

deleteIn()的描述