Remove value from object without mutation

后端 未结 8 770
天涯浪人
天涯浪人 2020-12-07 18:50

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:



        
相关标签:
8条回答
  • 2020-12-07 19:10

    My issue with the accepted answer, from an ESLint rule standard, if you try to destructure:

        const { notNeeded, alsoNotNeeded, ...rest } = { ...ogObject };
    

    the 2 new variables, notNeeded and alsoNotNeeded may throw a warning or error depending on your setup since they are now unused. So why create new vars if unused?

    I think you need to use the delete function truly.

    0 讨论(0)
  • 2020-12-07 19:17

    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

    0 讨论(0)
  • 2020-12-07 19:22

    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}
    
    0 讨论(0)
  • 2020-12-07 19:24

    one line solution

    const removeKey = (key, {[key]: _, ...rest}) => rest;
    
    0 讨论(0)
  • 2020-12-07 19:27

    With ES7 object destructuring:

    const myObject = {
      a: 1,
      b: 2,
      c: 3
    };
    const { a, ...noA } = myObject;
    console.log(noA); // => { b: 2, c: 3 }
    
    0 讨论(0)
  • 2020-12-07 19:29

    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.

    0 讨论(0)
提交回复
热议问题