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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/34401098/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 16:17:04  来源:igfitidea点击:

Remove a property in an object immutably

javascriptimmutabilityredux

提问by Vincent Taing

I am using Redux. In my reducer I'm trying to remove a property from an object like this:

我正在使用 Redux。在我的减速器中,我试图从这样的对象中删除一个属性:

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

And I want to have something like this without having to mutate the original state:

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

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

I tried:

我试过:

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

but for some reasons, it deletes the property from both states.

但由于某些原因,它从两个州中删除了该财产。

Could help me to do that?

可以帮我做吗?

回答by madebydavid

How about using destructuring assignmentsyntax?

如何使用解构赋值语法?

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 } }

回答by David L. Walsh

I find ES5 array methods like filter, mapand reduceuseful because they always return new arrays or objects. In this case I'd use Object.keysto iterate over the object, and Array#reduceto turn it back into an object.

我发现 ES5 数组方法像filter,map并且reduce很有用,因为它们总是返回新的数组或对象。在这种情况下,我会使用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;
    }, {})
});

回答by Dmitri

You can use _.omit(object, [paths])from lodashlibrary

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

path can be nested for example: _.omit(object, ['key1.key2.key3'])

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

回答by Ramon Diogo

Just use ES6 object destructuring feature

只需使用 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

回答by A???

That's because you are copying the value of state.cto the other object. And that value is a pointer to another javascript object. So, both of those pointers are pointing to the same object.

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

Try this:

尝试这个:

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;

You can also do a deep-copy of the object. See this questionand you'll find what's best for you.

您还可以对对象进行深层复制。看到这个问题,你会找到最适合你的。

回答by SebK

How about this:

这个怎么样:

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

It filters the key that should be deleted then builds a new object from the remaining keys and the initial object. The idea is stolen from Tyler McGinnes awesome reactjs program.

它过滤应该删除的键,然后从剩余的键和初始对象构建一个新对象。这个想法是从 Tyler McGinnes 很棒的 reactjs 程序中窃取的。

JSBin

JSBin

回答by Dominykas Mostauskis

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

Also, if looking for a functional programming toolkit, look at Ramda.

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

回答by Javier P

You may use Immutability helperin order to unset an attribute, in your case:

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

import update from 'immutability-helper';

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

回答by jian

As of 2019, another option is to use the Object.fromEntriesmethod. It has reached stage 4.

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

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

The nice thing about it is that it handles integer keys nicely.

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

回答by quotesBro

It's easy with Immutable.js:

使用Immutable.js很容易:

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

description of deleteIn()

deleteIn() 的描述