从对象中删除值而不进行变异

时间:2015-10-10 11:09:19

标签: javascript immutability

在不改变原始对象的情况下,从特定键的对象中删除值的好方法和简短方法是什么?

我想做类似的事情:

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

我知道这些任务有很多不变的库,但我想在没有库的情况下离开。但要做到这一点,一个要求是在整个代码中使用一种简单易用的方法,而不是将方法作为效用函数抽象出来。

E.g。要添加值,我会执行以下操作:

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

这很简短,易记,也不需要实用功能。

是否有类似的东西用于删除值? ES6非常受欢迎。

非常感谢!

9 个答案:

答案 0 :(得分:160)

更新

您可以使用棘手的Destructuring assignment

从对象中删除属性
const doSomething = (obj, prop) => {
  let {[prop]: omit, ...res} = obj
  return res
}

但是,如果要删除的属性名称是静态的,那么您可以使用简单的单行删除它:

let {lastname, ...o2} = o

最简单的方法就是或者你可以在变异之前克隆你的对象:

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

或者您可以使用omit function from lodash utility library

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

它可以作为lodash包的一部分提供,也可以作为独立的lodash.omit包提供。

答案 1 :(得分:13)

一线解决方案

public class NotifierEntity
{
    ICollection<SqlParameter> sqlParameters = new List<SqlParameter>();

    public String SqlQuery { get; set; }

    public String SqlConnectionString { get; set; }

    public ICollection<SqlParameter> SqlParameters
    {
        get
        {
            return sqlParameters;
        }
        set
        {
            sqlParameters = value;
        }
    }

    public static NotifierEntity FromJson(String value)
    {
        if (String.IsNullOrEmpty(value))
            throw new ArgumentNullException("NotifierEntity Value can not be null!");
        return new JavaScriptSerializer().Deserialize<NotifierEntity>(value);
    }
}

public static class NotifierEntityExtentions
{
    public static String ToJson(this NotifierEntity entity)
    {
        if (entity == null)
            throw new ArgumentNullException("NotifierEntity can not be null!");
        return new JavaScriptSerializer().Serialize(entity);
    }
}

public class PushSqlDependency
{
    static PushSqlDependency instance = null;
    readonly SqlDependencyRegister sqlDependencyNotifier;
    readonly Action<String> dispatcher;

    public static PushSqlDependency Instance(NotifierEntity notifierEntity, Action<String> dispatcher)
    {
        if (instance == null)
            instance = new PushSqlDependency(notifierEntity, dispatcher);
        return instance;
    }

    private PushSqlDependency(NotifierEntity notifierEntity, Action<String> dispatcher)
    {
        this.dispatcher = dispatcher;
        sqlDependencyNotifier = new SqlDependencyRegister(notifierEntity);
        sqlDependencyNotifier.SqlNotification += OnSqlNotification;
    }

    internal void OnSqlNotification(object sender, SqlNotificationEventArgs e)
    {
        dispatcher("Refresh123");
    }
}

public class SqlDependencyRegister
{
    public event SqlNotificationEventHandler SqlNotification;

    readonly NotifierEntity notificationEntity;

    internal SqlDependencyRegister(NotifierEntity notificationEntity)
    {
        this.notificationEntity = notificationEntity;
        RegisterForNotifications();
    }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security",
    "CA2100:Review SQL queries for security vulnerabilities")]
    void RegisterForNotifications()
    {
        using (var sqlConnection = new SqlConnection(notificationEntity.SqlConnectionString))
        using (var sqlCommand = new SqlCommand(notificationEntity.SqlQuery, sqlConnection))
        {
            foreach (var sqlParameter in notificationEntity.SqlParameters)
            {
                sqlCommand.Parameters.Add(sqlParameter);
            }

            sqlCommand.Notification = null;
            var sqlDependency = new SqlDependency(sqlCommand);
            sqlDependency.OnChange += OnSqlDependencyChange;
            if (sqlConnection.State == ConnectionState.Closed)
                sqlConnection.Open();
            sqlCommand.ExecuteNonQuery();
        }
    }

    void OnSqlDependencyChange(object sender, SqlNotificationEventArgs e)
    {
        if (SqlNotification != null)
            SqlNotification(sender, e);
        RegisterForNotifications();
    }
}

public delegate void SqlNotificationEventHandler(object sender, SqlNotificationEventArgs e);

答案 2 :(得分:13)

使用ES7对象分解:

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

答案 3 :(得分:3)

正如上面的评论中所建议的,如果您想扩展此项以从object移除多个项目,我想使用filter。和reduce

例如

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

答案 4 :(得分:1)

添加一些香料以提高性能。检查此螺纹波纹管

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

  

使用delete运算符会降低性能   V8隐藏类模式。一般建议不要使用   它。

     

或者,要删除对象自身的可枚举属性,我们可以   创建没有这些属性的新对象副本(例如,使用   lodash):

     

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

     

或者甚至将属性值定义为null或undefined(这是   序列化为JSON时被隐式忽略):

     

o.prop =未定义

您也可以使用破坏方式

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

还有一个更实用的示例:

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

如您所见,可以将[somePropsVarForDynamicName]: scopeVarName语法用于动态名称。并且您可以将所有内容放在方括号(新块)中,以便将其余部分收集在此之后。

这里有一个测试: enter image description here

exec:

enter image description here

或者我们可以使用类似的功能

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;
    }, {});
}

打字稿

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;
    }, {});
}

用法:

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

a = deleteProps(a, 'propB'); 

// or 

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

这样,可以创建一个新对象。并且保留对象的快速属性。哪个可能重要或重要。如果映射和对象将被多次访问。

关联undefined也是一个不错的选择。当您负担得起时。对于键,您也可以检查该值。例如,要获取所有活动键,您可以执行以下操作:

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.

未定义虽然不适用于大列表。否则随着时间的推移就会有很多道具加入其中。随着内存使用量的增长,而且永远不会清除。因此,这取决于用法。只是创建一个新对象似乎是个好方法。

然后Premature optimization is the root of all evil就会出现。因此,您需要注意一些折衷。以及需要什么,不需要什么。

关于lodash的_.omit()的注意事项

它已从版本5中删除。您在存储库中找不到它。这里是一个谈论它的问题。

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

v8

您可以查看此书,https://v8.dev/blog/fast-properties

答案 5 :(得分:1)

如果您尝试解构,我的问题是来自ESLint规则标准的可接受的答案

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

这两个新变量notNeededalsoNotNeeded可能会因您的设置而引发警告或错误,因为它们现在未使用。那么,为什么要创建未使用的新变量呢?

我认为您需要真正使用delete函数。

答案 6 :(得分:0)

具有lodash cloneDeep和删除

(注意:lodash克隆可代替浅对象使用)

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}

答案 7 :(得分:0)

对于我的代码,我想要map()的返回值的简短版本,但多行/多操作运算的解决方案却“丑陋”。关键功能是旧的void(0)可以解析为undefined

let o2 = {...o, age: 31, lastname: void(0)};

该属性保留在对象中:

console.log(o2) // {firstname: "Jane", lastname: undefined, age: 31}

但是传输框架会帮我杀死它(b.c. stringify):

console.log(JSON.stringify(o2)) // {"firstname":"Jane","age":31}

答案 8 :(得分:0)

我为我写了关于问题的大函数。该函数将 props(不是它本身,只有值)、数组等的所有值清除为多维。

注意:函数清除数组中的元素,数组变为空数组。也许这种情况可以添加为可选功能。

https://gist.github.com/semihkeskindev/d979b169e4ee157503a76b06573ae868

function clearAllValues(data, byTypeOf = false) {

    let clearValuesTypeOf = {
        boolean: false,
        number: 0,
        string: '',
    }

    // clears array if data is array
    if (Array.isArray(data)) {
        data = [];
    } else if (typeof data === 'object' && data !== null) {
        // loops object if data is object
        Object.keys(data).forEach((key, index) => {
            // clears array if property value is array
            if (Array.isArray(data[key])) {
                data[key] = [];
            } else if (typeof data[key] === 'object' && data !== null) {
                data[key] = this.clearAllValues(data[key], byTypeOf);
            } else {
                // clears value by typeof value if second parameter is true
                if (byTypeOf) {
                    data[key] = clearValuesTypeOf[typeof data[key]];
                } else {
                    // value changes as null if second parameter is false
                    data[key] = null;
                }
            }
        });
    } else {
        if (byTypeOf) {
            data = clearValuesTypeOf[typeof data];
        } else {
            data = null;
        }
    }

    return data;
}

这是一个没有删除道具清除所有值的示例

let object = {
    name: 'Semih',
    lastname: 'Keskin',
    brothers: [
        {
            name: 'Melih Kayra',
            age: 9,
        }
    ],
    sisters: [],
    hobbies: {
        cycling: true,
        listeningMusic: true,
        running: false,
    }
}

console.log(object);
// output before changed: {"name":"Semih","lastname":"Keskin","brothers":[{"name":"Melih Kayra","age":9}],"sisters":[],"hobbies":{"cycling":true,"listeningMusic":true,"running":false}}

let clearObject = clearAllValues(object);

console.log(clearObject);
// output after changed: {"name":null,"lastname":null,"brothers":[],"sisters":[],"hobbies":{"cycling":null,"listeningMusic":null,"running":null}}

let clearObject2 = clearAllValues(object);

console.log(clearObject2);
// output after changed by typeof: {"name":"","lastname":"","brothers":[],"sisters":[],"hobbies":{"cycling":false,"listeningMusic":false,"running":false}}