如何克隆一个JavaScript对象,除了一个键?

我有一个平面JS对象:

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

我想克隆对象除了一个元素:

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

最简单的方法是什么(如果可能的话,更倾向于使用es6/7)?

382378 次浏览

也许是这样的:

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

这样够好吗?或者c实际上不能被复制?

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

您可以为它编写一个简单的helper函数。Lodash有一个同名的类似函数:省略

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快。赋值和删除然后:http://jsperf.com/omit-key

JavaScript中有一个解构的任务语法可以使用

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


// skips the "Unused variable" warning
let {b: _, ...rest} = obj;


// removes property based on the dynamic key
const dynamicKey = "b";
let {[dynamicKey]: _, ...rest} = obj;
现代浏览器已经开箱即用地支持它。 看到:# EYZ0 < / p >

对于旧的浏览器版本,有一个选项可以使用巴别塔来支持解构赋值。# EYZ1成:

"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"]);

补充一下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};

<一个href = " https://babeljs.io/repl/ ? babili = false&评估= true& lineWrap = false&预设= es2015 % 2 ces2015-loose % 2 creact % 2 cstage-0&代码= const % 20 x % 7英航20% 3 d % 20% % % 201% 2 3 3 c % 20 b % % 202% 2 3 c % 20 c % % 203% 2 c % 20 z % 3 a26 % 7 d % 3 b % 0 a % 0 aconst % 20 objectWithoutKey % 20% 3 d % 20(对象% 2 c % 20键)3 d % 3 e % % 20% 20% 7 b % 0 a % 20% 20 const % 20% 7 b % 5 3 bkey % 5 d % % 20 deletedkey % 2 c % 20…otherKeys % 7 d % 20% 3 d对象% 3 b % % 20 0 20% % 20返回% 20 otherKeys % 3 b % 0 a % d % 0 a % 0 7 aconsole.log (objectWithoutKey (x % 27 b 2 c % 20% % 27)) % 3 b % 2 f % 2 f % 20% 20% 7英航% % 201% 2 3 3 c % 20 c % % 203%2C%20z%3A26%7D% 0console .log(x)%3B%20%2F%2F%20%7Ba%3A%201%2C%20b%3A% 20c%3A% 20% 2C%20z%3A26%7D% 3b&a;experimental=true&loose=true&spec=false"> Babel REPL中的演示

来源:

  • https://twitter.com/ydkjs/status/699845396084846592 < a href = " https://twitter.com/ydkjs/status/699845396084846592 " > < / >

对于那些不能使用ES6的人,你可以使用lodashunderscore

_.omit(x, 'b')

或# EYZ0。

R.omit('b', x)

如果你正在处理一个巨大的变量,你不希望复制它,然后删除它,因为这将是低效的。

一个简单的带有hasOwnProperty检查的for循环应该可以工作,而且它更适合未来的需求:

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

Lodash # EYZ0

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

嘿,当你试图复制一个对象然后删除一个属性时,你似乎遇到了引用问题。你必须在某个地方分配基本变量,这样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"}

你也可以使用展开运算符

const source = { a: 1, b: 2, c: 3, z: 26 }
const copy = { ...source, ...{ b: undefined } } // { a: 1, c: 3, z: 26 }

我用的是ESNext one liner

const obj = { a: 1, b: 2, c: 3, d: 4 }
const clone = (({ b, c, ...o }) => o)(obj) // remove b and c
console.log(clone)

这个呢? 我从来没有发现这种模式周围,但我只是试图排除一个或多个属性,而不需要创建一个额外的对象。这似乎是做的工作,但有一些副作用,我不能看到。

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


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


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

使用对象解构

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}

我以Redux减速机为例:

 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

上述使用结构化的解决方案确实受到一个事实的影响,即你有一个使用过的变量,如果你使用它,可能会引起ESLint的抱怨。

下面是我的解决方案:

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

在大多数平台上(除了IE,除非使用Babel),你还可以这样做:

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

这里有一个省略动态键的选项,我相信还没有提到:

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

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'));

下面是我对Typescript的看法,稍微从@Paul的答案衍生出来,并使用减少代替。

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']))

我有一个对象:选项和一些键

  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,你可以放置你想要排除的属性的值

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

const newObj ={...obj, [key]: undefined}

您可以使用lodash库来实现这一目的(如果您需要在项目中使用大量数组/对象数组/对象)。

使用lodash deepclone函数你可以做:

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

首先将整个对象克隆为新的对象,然后从克隆对象中删除所需的键,这样原始的键就不会受到影响。

如果使用typescript, delete关键字解决方案将抛出编译错误,因为它破坏了实例化的对象的契约。ES6扩展操作符解决方案(const {x, ...keys} = object)可能会抛出一个错误,这取决于您在项目中使用的检测配置,因为x变量没有开始使用。所以我想出了这个解决方案:

const cloneObject = Object.entries(originalObject)
.filter(entry => entry[0] !== 'keyToRemove')
.reduce((acc, keyValueTuple) => ({ ...acc, [keyValueTuple[0]]: keyValueTuple[1] }), {});

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

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

这里有一个Typescript方法可以做到这一点。期望2个参数,对象和一个包含键的字符串数组被删除:

removeKeys(object: { [key: string]: any }, keys: string[]): { [key: string]: any } {
const ret: { [key: string]: any } = {};


for (const key in object) {
if (!keys.includes(key)) {
ret[key] = object[key];
}
}


return ret;
}