克隆除一个键之外的js对象

时间:2016-01-09 21:03:29

标签: javascript ecmascript-6 ecmascript-harmony ecmascript-7

我有一个扁平的JS对象:

{a: 1, b: 2, c: 3, ..., z:26}

我想克隆除一个元素之外的对象:

{a: 1, c: 3, ..., z:26}

最简单的方法是什么(如果可能,最好使用es6 / 7)?

28 个答案:

答案 0 :(得分:277)

如果您使用Babel,则可以使用以下语法将属性b从x复制到变量b,然后将其余属性复制到变量y

let x = {a: 1, b: 2, c: 3, z:26};
let {b, ...y} = x;

it will be transpiled进入:

"use strict";

function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }

var x = { a: 1, b: 2, c: 3, z: 26 };
var b = x.b;

var y = _objectWithoutProperties(x, ["b"]);

答案 1 :(得分:102)

var clone = Object.assign({}, {a: 1, b: 2, c: 3});
delete clone.b;

或者如果您接受未定义的属性:

var clone = Object.assign({}, {a: 1, b: 2, c: 3}, {b: undefined});

答案 2 :(得分:53)

要添加到Ilya Palkin的答案:您甚至可以动态删除密钥:

const x = {a: 1, b: 2, c: 3, z:26};

const objectWithoutKey = (object, key) => {
  const {[key]: deletedKey, ...otherKeys} = object;
  return otherKeys;
}

console.log(objectWithoutKey(x, 'b')); // {a: 1, c: 3, z:26}
console.log(x); // {a: 1, b: 2, c: 3, z:26};

Demo in Babel REPL

来源:

答案 3 :(得分:50)

对于无法使用ES6的用户,可以使用<iframe allowfullscreen="" frameborder="0" height="360" src="https://www.youtube.com/embed/Some_Video" width="640"></iframe> lodash

underscore

_.omit(x, 'b')

ramda

答案 4 :(得分:18)

您可以为它编写一个简单的辅助函数。 Lodash具有相同的功能,名称相同:omit

function omit(obj, omitKey) {
  return Object.keys(obj).reduce((result, key) => {
    if(key !== omitKey) {
       result[key] = obj[key];
    }
    return result;
  }, {});
}

omit({a: 1, b: 2, c: 3}, 'c')  // {a: 1, b: 2}

另请注意,它比Object.assign快,然后删除:http://jsperf.com/omit-key

答案 5 :(得分:12)

我使用这种单线ES6语法

BAD.DATA

答案 6 :(得分:9)

也许是这样的:

var copy = Object.assign({}, {a: 1, b: 2, c: 3})
delete copy.c;

这够好吗?或者c实际上是否会被复制?

答案 7 :(得分:7)

如何?

class UserStatisticSerializer(serializers.Serializer):
    user = serializers.SerializerMethodField()      # not sure on these fields
    max_date = serializers.SerializerMethodField()  # not sure on these fields
    min_date = serializers.SerializerMethodField()  # not sure on these fields


    statistics = StatisticSerializer(many=True) # <---

    class Meta:
            model = User
            fields = [
                'id', 'first_name', 'last_name', 'email', 'gender', 'ip_address',
                'statistics' # <---
            ]

答案 8 :(得分:6)

当你试图复制一个对象然后删除一个属性时,嘿,好像你会参与引用问题。在某些地方你必须分配原始变量,以便javascript创建一个新值。

我使用的简单技巧(可能是可怕的)是

var obj = {"key1":"value1","key2":"value2","key3":"value3"};

// assign it as a new variable for javascript to cache
var copy = JSON.stringify(obj);
// reconstitute as an object
copy = JSON.parse(copy);
// now you can safely run delete on the copy with completely new values
delete copy.key2

console.log(obj)
// output: {key1: "value1", key2: "value2", key3: "value3"}
console.log(copy)
// output: {key1: "value1", key3: "value3"}

答案 9 :(得分:6)

以下是我认为尚未提及的忽略动态键的选项:

const obj = { 1: 1, 2: 2, 3: 3, 4: 4 };
const removeMe = 1;

const { [removeMe]: removedKey, ...newObj } = obj;

removeMe的别名为removedKey,并被忽略。 newObj成为{ 2: 2, 3: 3, 4: 4 }。请注意,删除的键不存在,其值不只是设置为undefined

答案 10 :(得分:4)

Lodash omit

let source = //{a: 1, b: 2, c: 3, ..., z:26}
let copySansProperty = _.omit(source, 'b');
// {a: 1, c: 3, ..., z:26}

答案 11 :(得分:3)

我最近以非常简单的方式做到了:

const obj = {a: 1, b: 2, ..., z:26};

仅使用 spread运算符即可分隔不需要的属性:

const {b, ...rest} = obj;

...和 object.assign 仅包含“其余”部分:

const newObj = Object.assign({}, {...rest});

答案 12 :(得分:3)

使用对象分解

const omit = (prop, { [prop]: _, ...rest }) => rest;
const obj = { a: 1, b: 2, c: 3 };
const objWithoutA = omit('a', obj);
console.log(objWithoutA); // {b: 2, c: 3}

答案 13 :(得分:2)

您还可以使用传播运算符来执行此操作

select * from pg_namespace where nspowner in (select usesysid from pg_user where usename in ('one', 'two'));

答案 14 :(得分:2)

那呢? 我从来没有发现这种模式,但是我只是试图排除一个或多个属性,而无需创建额外的对象。这似乎可以完成工作,但是有一些副作用我看不到。当然不是很可读。

const postData = {
   token: 'secret-token',
   publicKey: 'public is safe',
   somethingElse: true,
};

const a = {
   ...(({token, ...rest} = postData) => (rest))(),
}

/**
a: {
   publicKey: 'public is safe',
   somethingElse: true,
}
*/

答案 15 :(得分:2)

如果你正在处理一个巨大的变量,你不想复制它然后删除它,因为这样效率很低。

带有hasOwnProperty检查的简单for循环应该有效,并且它更适合未来的需求:

for(var key in someObject) {
        if(someObject.hasOwnProperty(key) && key != 'undesiredkey') {
                copyOfObject[key] = someObject[key];
        }
}

答案 16 :(得分:2)

我不知道你到底想用它做什么,所以我不确定这是否适合你,但我只是做了以下工作并且它适用于我的用例:

run()

答案 17 :(得分:1)

如果您使用 Ramda,您可以使用其 omitclone 函数对您的对象进行深度克隆并省略不必要的字段。

var object = {a: 1, b: 2, c: 3, y:25, z:26};
R.clone(R.omit(["z", "y"], object));

答案 18 :(得分:1)

我以这种方式完成了它,例如我的Redux reducer中的例子:

 const clone = { ...state };
 delete clone[action.id];
 return clone;

换句话说:

const clone = { ...originalObject } // note: original object is not altered
delete clone[unwantedKey]           // or use clone.unwantedKey or any other applicable syntax
return clone                        // the original object without the unwanted key

答案 19 :(得分:1)

const x = {obj1: 1, pass: 2, obj2: 3, obj3:26};

const objectWithoutKey = (object, key) => {
  const {[key]: deletedKey, ...otherKeys} = object;
  return otherKeys;
}

console.log(objectWithoutKey(x, 'pass'));

答案 20 :(得分:1)

上面使用结构化的解决方案的确存在一个事实,那就是您拥有一个已使用的变量,如果使用该变量,可能会引起ESLint的抱怨。

这是我的解决方案:

const src = { a: 1, b: 2 }
const result = Object.keys(src)
  .reduce((acc, k) => k === 'b' ? acc : { ...acc, [k]: src[k] }, {})

在大多数平台上(除非使用Babel,否则IE除外),您也可以这样做:

const src = { a: 1, b: 2 }
const result = Object.fromEntries(
  Object.entries(src).filter(k => k !== 'b'))

答案 21 :(得分:0)

我有一个object,我想在使用其方法后将其删除。这就是对我有用的。


/* Sample data */
let items = [
  {
    name: 'John',
    doc: {
      set: async (item) => {/*...sets docs on remote server*/}
    }
  },{
    name: 'Mary',
    doc: {
      set: async (item) => {/*...sets docs on remote server*/}
    }
  },{
    name: 'Jack',
    doc: {
      set: async (item) => {/*...sets docs on remote server*/}
    }
  }
]

/* mapping to promises */
const promises = items.map(({doc, ...item}) => doc.set(item)); 
// utilized doc and utilized `rest` of the items :)


祝你好运:)

答案 22 :(得分:0)

这是我在打字稿上的两美分,略微来自@Paul的回答,而使用 reduce

function objectWithoutKey(object: object, keys: string[]) {
    return keys.reduce((previousValue, currentValue) => {
        // @ts-ignore
        const {[currentValue]: undefined, ...clean} = previousValue;
        return clean
    }, object)
}

// usage
console.log(objectWithoutKey({a: 1, b: 2, c: 3}, ['a', 'b']))

答案 23 :(得分:0)

我有一个名为: options 并带有一些键的对象

  let options = {       
        userDn: 'somePropertyValue',
        username: 'someValue',
        userSearchBase: 'someValue',
        usernameAttribute: 'uid',
        userPassword: 'someValue'
    }

我想记录所有对象的excelp userPassword属性,因为我正在测试某些东西,我正在使用此代码:

console.log(Object.keys(options).map(x => x + ': ' + (x === "userPassword" ? '---' : options[x])));

如果要使其动态,只需创建一个函数即可,而不是显式放置 userPassword ,您可以放置​​要排除的属性的值

答案 24 :(得分:0)

这也应该做到;我很确定'delete'也可以与关联数组一起使用:

var copy = (obj, del)=>{
    delete obj.del;
    return obj;
}

答案 25 :(得分:0)

如果您使用 typescript,delete 关键字解决方案将引发编译错误,因为它违反了您实例化的对象的约定。 ES6 扩展运算符解决方案 (import numpy as np import pandas as pd import string from codetiming import Timer np.random.seed(10) # Construct a toy dataframe RANDS_CHARS = np.array(list(string.ascii_letters + string.digits), dtype=(np.str_, 1)) num_firsts = 1000 firsts = ''.join(np.random.choice(RANDS_CHARS, num_firsts)) print(f"N: {num_firsts}") tups = [] num_third = 4 num_fourth = 3 for i, first in enumerate(firsts): # Each "first" group has its own unique set of "third" and "fourth" index possibilities. thirds = np.random.choice(range(i * 100, i * 100 + 50), size=num_third, replace=False) # It's possible for the positive group's "third" index to be identical to one of the negative groups. if np.random.uniform() < 0.1: thirds[0] = thirds[1] fourths = np.random.choice(range(i * 100 + 1000, i * 100 + 1050), size=num_fourth, replace=False) for (i, third) in enumerate(thirds): if i == 0: second = "positive" else: second = "negative" for fourth in fourths: tups.append((first, second, third, fourth)) num_data = len(tups) index = pd.MultiIndex.from_tuples(tups, names=["first", "second", "third", "fourth"]) x = np.random.randint(low=0, high=2, size=num_data, dtype=bool) input_df = pd.DataFrame(index=index, data={"x": x}).reset_index() # Complication: Not all groups when grouped by "fourth" will have the same indices. Most indices will be shared by most # "fourth" groups, but the intersection is not complete. mask = np.ones(num_data, dtype=bool) mask[[17, 18]] = False input_df = input_df[mask] input_df = input_df.set_index(["first", "second", "third", "fourth"]) dfs = [] with Timer(text="Douple loop {:.3f} s"): # For for each "first" group: for first, first_df in input_df.groupby("first"): # Separate the positive group and negative groups positive_mask = first_df.index.get_level_values("second") == "positive" first_df = first_df.droplevel(["first"]) positive_df = first_df[positive_mask] negative_dfs = first_df[~positive_mask] positive_df = positive_df.droplevel(["second", "third"]) # Do some computations w.r.t. each negative "third" group and its corresponding positive group. for third, negative_df in negative_dfs.groupby("third"): negative_df = negative_df.droplevel(["second", "third"]) # Compare the positive/negative group based on their "fourth" indices. Note that for indices not in their # intersection "False" is assigned. true_true = negative_df["x"] & positive_df["x"] true_false = negative_df["x"] & ~positive_df["x"] false_false = ~negative_df["x"] & ~positive_df["x"] false_true = ~negative_df["x"] & positive_df["x"] df = pd.DataFrame({ "true_true": true_true, "true_false": true_false, "false_false": false_false, "false_true": false_true }).reset_index() df["first"] = first df["second"] = "negative" df["third"] = third dfs.append(df) # Output: A big dataframe of the computed values of all the negative "third" groups. output_df = pd.concat(dfs) output_df = output_df.set_index(["first", "second", "third", "fourth"], verify_integrity=True).sort_index() with Timer(text="Vectorized {:.3f} s"): # Get positive/negative entries side by side dfi = input_df['x'].unstack(level=['second']) # Copy positive entries into a new column according to the {"first" x "fourth"} index of each for comparison with # negative indices. dfi["_positive"] = input_df["x"].loc[:, "positive", :, :].droplevel("third").reindex( dfi.index.droplevel("third")).values # Drop the "third" groups where there was no negative entry to begin with. dfi = dfi[~dfi["negative"].isna()] # Do the computation. dfi['true_true'] = dfi["negative"] & dfi["_positive"] dfi['true_false'] = dfi["negative"] & ~dfi["_positive"] dfi['false_false'] = ~dfi["negative"] & ~dfi["_positive"] dfi['false_true'] = ~dfi["negative"] & dfi["_positive"] # Reformat to match output_df indices for comparison dfi = dfi.drop(columns=["positive", "negative", "_positive"]) dfi["second"] = "negative" dfi = dfi.set_index("second", append=True).reorder_levels(["first", "second", "third", "fourth"]) # Filter out the empty rows from the correct, slow method to check correctness of the rows we did calculate. compare_rows = output_df.any(axis=1) assert output_df[compare_rows].equals(dfi) ) 可能会根据您在项目中使用的 linting 配置引发错误,因为未使用 const {x, ...keys} = object 变量。所以我想出了这个解决方案:

x

它使用Object.entries方法(获取原始对象的键/值对数组)和数组方法filterreduce的组合来解决问题。它看起来很冗长,但我认为有一个单行可链接的解决方案很好。

答案 26 :(得分:0)

使用 lodash 干净快速,使用此解决方案,您可以删除多个键,并且无需更改原始对象。这在不同情况下更具可扩展性和可用性:

import * as _ from 'lodash';

function cloneAndRemove(
    removeTheseKeys: string[],
    cloneObject: any,
): object | never {
    const temp = _.cloneDeep(cloneObject);
    removeTheseKeys.forEach((key) => {
        delete temp[key];
    });

    return temp;
}

export { cloneAndRemove };

答案 27 :(得分:-1)

使用 loadash deepclone 功能你可以:

const _obj = _.cloneDeep(obj);
delete _obj.key;

首先将整个对象克隆到新对象中,然后从克隆对象中删除所需的键,以免影响原始对象。