Remove value from object without mutation

…衆ロ難τιáo~ 提交于 2019-11-28 20:43:16

问题


What's a good and short way to remove a value from an object at a specific key without mutating the original object?

I'd like to do something like:

let o = {firstname: 'Jane', lastname: 'Doe'};
let o2 = doSomething(o, 'lastname');
console.log(o.lastname); // 'Doe'
console.log(o2.lastname); // undefined

I know there are a lot of immutability libraries for such tasks, but I'd like to get away without a library. But to do this, a requirement would be to have an easy and short way that can be used throughout the code, without abstracting the method away as a utility function.

E.g. for adding a value I do the following:

let o2 = {...o1, age: 31};

This is quite short, easy to remember and doesn't need a utility function.

Is there something like this for removing a value? ES6 is very welcome.

Thank you very much!


回答1:


Update:

You could remove a property from an object with a tricky Destructuring assignment:

const doSomething = (obj, prop) => {
  let {[prop]: omit, ...res} = obj
  return res
}

Though, if property name you want to remove is static, then you could remove it with a simple one-liner:

let {lastname, ...o2} = o

The easiest way is simply to Or you could clone your object before mutating it:

const doSomething = (obj, prop) => {
  let res = Object.assign({}, obj)
  delete res[prop]
  return res
}

Alternatively you could use omit function from lodash utility library:

let o2 = _.omit(o, 'lastname')

It's available as a part of lodash package, or as a standalone lodash.omit package.




回答2:


With ES7 object destructuring:

const myObject = {
  a: 1,
  b: 2,
  c: 3
};
const { a, ...noA } = myObject;
console.log(noA); // => { b: 2, c: 3 }



回答3:


one line solution

const removeKey = (key, {[key]: _, ...rest}) => rest;



回答4:


As suggested in the comments above if you want to extend this to remove more than one item from your object I like to use filter. and reduce

eg

    const o = {
      "firstname": "Jane",
      "lastname": "Doe",
      "middlename": "Kate",
      "age": 23,
      "_id": "599ad9f8ebe5183011f70835",
      "index": 0,
      "guid": "1dbb6a4e-f82d-4e32-bb4c-15ed783c70ca",
      "isActive": true,
      "balance": "$1,510.89",
      "picture": "http://placehold.it/32x32",
      "eyeColor": "green",
      "registered": "2014-08-17T09:21:18 -10:00",
      "tags": [
        "consequat",
        "ut",
        "qui",
        "nulla",
        "do",
        "sunt",
        "anim"
      ]
    };

    const removeItems = ['balance', 'picture', 'tags']
    console.log(formatObj(o, removeItems))

    function formatObj(obj, removeItems) {
      return {
        ...Object.keys(obj)
          .filter(item => !isInArray(item, removeItems))
          .reduce((newObj, item) => {
            return {
              ...newObj, [item]: obj[item]
            }
          }, {})
      }
    }

    function isInArray(value, array) {
      return array.indexOf(value) > -1;
    }



回答5:


To add some spice bringing in Performance. Check this thread bellow

https://github.com/googleapis/google-api-nodejs-client/issues/375

The use of the delete operator has performance negative effects for the V8 hidden classes pattern. In general it's recommended do not use it.

Alternatively, to remove object own enumerable properties, we could create a new object copy without those properties (example using lodash):

_.omit(o, 'prop', 'prop2')

Or even define the property value to null or undefined (which is implicitly ignored when serializing to JSON):

o.prop = undefined

You can use too the destructing way

const {remov1, remov2, ...new} = old;
old = new;

And a more practical exmple:

this._volumes[this._minCandle] = undefined;
{ 
     const {[this._minCandle]: remove, ...rest} = this._volumes;
     this._volumes = rest; 
}

As you can see you can use [somePropsVarForDynamicName]: scopeVarName syntax for dynamic names. And you can put all in brackets (new block) so the rest will be garbage collected after it.

Here a test:

exec:

Or we can go with some function like

function deleteProps(obj, props) {
    if (!Array.isArray(props)) props = [props];
    return Object.keys(obj).reduce((newObj, prop) => {
        if (!props.includes(prop)) {
            newObj[prop] = obj[prop];
        }
        return newObj;
    }, {});
}

for typescript

function deleteProps(obj: Object, props: string[]) {
    if (!Array.isArray(props)) props = [props];
    return Object.keys(obj).reduce((newObj, prop) => {
        if (!props.includes(prop)) {
            newObj[prop] = obj[prop];
        }
        return newObj;
    }, {});
}

Usage:

let a = {propH: 'hi', propB: 'bye', propO: 'ok'};

a = deleteProps(a, 'propB'); 

// or 

a = deleteProps(a, ['propB', 'propO']);

This way a new object is created. And the fast property of the object is kept. Which can be important or matter. If the mapping and the object will be accessed many many times.

Also associating undefined can be a good way to go with. When you can afford it. And for the keys you can too check the value. For instance to get all the active keys you do something like:

const allActiveKeys = Object.keys(myObj).filter(k => myObj[k] !== undefined);
//or
const allActiveKeys = Object.keys(myObj).filter(k => myObj[k]); // if any false evaluated value is to be stripped.

Undefined is not suited though for big list. Or development over time with many props to come in. As the memory usage will keep growing and will never get cleaned. So it depend on the usage. And just creating a new object seem to be the good way.

Then the Premature optimization is the root of all evil will kick in. So you need to be aware of the trade off. And what is needed and what's not.

Note about _.omit() from lodash

It's removed from version 5. You can't find it in the repo. And here an issue that talk about it.

https://github.com/lodash/lodash/issues/2930

v8

You can check this which is a good reading https://v8.dev/blog/fast-properties




回答6:


with lodash cloneDeep and delete

(note: lodash clone can be used instead for shallow objects)

const obj = {a: 1, b: 2, c: 3}
const unwantedKey = 'a'

const _ = require('lodash')
const objCopy = _.cloneDeep(obj)
delete objCopy[unwantedKey]
// objCopy = {b: 2, c: 3}


来源:https://stackoverflow.com/questions/33053310/remove-value-from-object-without-mutation

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!