如何克隆除一个键之外的 JavaScript 对象

How can I clone a JavaScript object except for one key?

本文关键字:对象 JavaScript 一个 何克隆      更新时间:2023-09-26

我有一个平面JS对象:

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

我想克隆对象,但一个元素除外:

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

最简单的方法是什么(如果可能的话,更喜欢使用 es6/7(?

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;

现代浏览器已经开箱即用地支持它。参见:JavaScript 运算符:解构赋值:Rest in Object

对于旧的浏览器版本,有一个选项可以使用 Babel 来支持解构赋值。它将被转换为:

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

我使用这个 ESNext 一行

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

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

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

_.omit(x, 'b')

或者ramda.

R.omit('b', x)

补充一下伊利亚·帕尔金的答案: 您甚至可以动态删除键:

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

巴别塔 REPL 中的演示

源:

  • https://twitter.com/ydkjs/status/699845396084846592

您可以为其编写一个简单的帮助程序函数。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.assign 和删除更快,然后:http://jsperf.com/omit-key

这是一个用于省略动态键的选项,我认为尚未提及:

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

也许是这样的:

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

这够好吗?还是c真的不能被复制?

使用对象解构

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}

嘿,

当您尝试复制对象然后删除属性时,您似乎遇到了引用问题。在某个地方,你必须分配原始变量,以便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 }

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

const postData = {
   token: 'secret-token',
   publicKey: 'public is safe',
   somethingElse: true,
};
const a = {
   ...(({token, ...rest} = postData) => (rest))(),
}
/**
a: {
   publicKey: 'public is safe',
   somethingElse: true,
}
*/

Lodash 省略

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

我是这样完成的,作为我的 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

上述使用结构化的解决方案确实存在这样一个事实,即您有一个已使用的变量,如果您使用它,可能会导致 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'))
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'));

我在这里使用对象解构。我已将密码分成变量,其余变量包含除密码之外的所有对象属性和值。注意:其余不是固定关键字,在这里您可以相应地命名它

const obj = {name:"john", password:"Abcds12@", id:"125455"}
const {password,...rest} = obj;
console.log(rest);

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

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

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

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

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

如果您使用的是打字稿,则 delete 关键字解决方案将引发编译错误,因为它会破坏您实例化的对象的协定。ES6 扩展运算符解决方案 ( const {x, ...keys} = object ( 可能会抛出错误,具体取决于您在项目中使用的 linting 配置,因为 x 变量不是良性的。所以我想出了这个解决方案:

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

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

这是我

在 Typescript 上的两分钱,稍微来自 @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']))

我有一个名为:带有一些键的选项

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

我想记录所有对象 excelp 用户密码属性,因为我正在测试某些东西,我正在使用以下代码:

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

如果你想让它动态化,只需创建一个函数,而不是显式放置userPassword,你可以放置你想要排除的属性的值

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

您可以使用 lodash 库来实现此目的(如果您需要在项目中处理大量数组/对象数组/对象

(。

使用 lodash 深度克隆函数 您可以执行以下操作:

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

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