648

I have a flat JS object:

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

I want to clone the object except for one element:

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

What's the easiest way to do this (preferring to use es6/7 if possible)?

jasonmerino
  • 3,220
  • 1
  • 21
  • 38
fox
  • 15,428
  • 20
  • 55
  • 85
  • 3
    Very careful with answers on this question, almost all of them at this time don't clone **Deeply** the rest of object. They are doing just a **Shallow** clone. All descendants properties of children props are passed by reference and can be changed through other variables. Please see https://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-deep-clone-an-object-in-javascript. As of 2023, for the given example use `structuredClone` fallbacking to `JSON.parse(JSON.stringify` method – Andre Figueiredo Jul 13 '23 at 21:56
  • ^^^ this is an excellent caveat – fox Jul 23 '23 at 03:59

25 Answers25

877

There is a Destructuring assignment syntax in JavaScript that can be used

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;

Modern browsers already support it out of the box. See: JavaScript operator: Destructuring assignment: Rest in objects

For old browser versions there is an option to use Babel to support destructuring assignment. It will be transpiled into:

"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
  • 14,687
  • 2
  • 23
  • 36
  • 91
    If you lint your code for unused variables, this will result in an "Unused variable 'b'." warning though. – Ross Allen Sep 02 '16 at 17:15
  • 1
    how would the syntax look if you had `let x = [{a: 1, b: 2, c: 3, z:26}, {a: 5, b: 6, c: 7, z:455}];` – ke3pup Sep 09 '16 at 06:26
  • you can use [Array.prototype.map()](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/map) for array. ```let y = x.map(item => { /* remove one key from the item and return it */ })``` – Ilya Palkin Sep 09 '16 at 08:04
  • 33
    @RossAllen There is an option [`ignoreRestSiblings`](http://eslint.org/docs/rules/no-unused-vars#ignorerestsiblings) that was added in v3.15.0 (February 3, 2017). See: [commit c59a0ba](https://github.com/eslint/eslint/commit/c59a0ba) – Ilya Palkin Mar 07 '17 at 13:08
  • 7
    @IlyaPalkin Interesting. It feels a bit lazy though because it doesn't change the fact that there is a `b` in scope. – Ross Allen Mar 07 '17 at 16:50
  • 2
    If you're getting Module build failed: SyntaxError: Unexpected token, you probably need to add the babel rest spread transform plugin. See babeljs.io/docs/plugins/transform-object-rest-spread – jsaven Jan 20 '18 at 04:08
  • What is this syntax called? – CodyBugstein Mar 18 '18 at 03:19
  • 1
    [Destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) I think – Ilya Palkin Mar 19 '18 at 15:50
  • Even though the opposite was never stated on this subject and this doesn't invalidate the solution, it might be worth noting that such feature performs a **shallow** copy: if `x` contained an object property, and since an object is a reference (https://codeburst.io/explaining-value-vs-reference-in-javascript-647a975e12a0), you could by mistake modify a nested value inside of `x` while modifying it in `y`. – papillon Feb 19 '19 at 09:27
  • 1
    As a side effect of what @RossAllen mentioned If you want to remove the same property from multiple objects you'll need to use var. Otherwise, you'll get an error for redeclaring a let variable. (In my case this came up in react for diffing state and nextState minus one property in componentShouldUpdate) – Arye Eidelman Aug 15 '19 at 03:40
  • if `bName` - is the name of subject key - this does not work: `let {[bName], ...y} = x;` I am uninstalling node right now, it not capable of doing just what we want!!!!1111 (that was oneliner, one function) – xakepp35 Sep 09 '19 at 15:14
  • 2
    Thanks for the answer. You don't necessarily need Babel for this syntax anymore: https://caniuse.com/#feat=mdn-javascript_operators_destructuring_rest_in_objects – adabru Dec 27 '19 at 09:46
  • 3
    To avoid "Unused variable" warning and still using the spread operator you can do: `let y = {...x}; delete y.b;` – Jingyi Wang Mar 30 '20 at 13:30
  • 7
    I did a `let { b: _b, ...y } = x;` to skip the "Unused variable" warning. – Waseem May 20 '21 at 00:54
  • 1
    When the key you want to remove is dynamic do: `const { [dynamicKey]: _, ...rest } = obj;` – nezort11 Nov 17 '22 at 15:33
259

I use this 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)
vdegenne
  • 12,272
  • 14
  • 80
  • 106
  • 27
    Instead of wrapping in array and `map` you can do: `(({b, c, ...others}) => ({...others}))(obj)` – bucabay Dec 22 '18 at 10:51
  • 2
    @bucabay: Brilliant! That's the best answer of the lot! Standards compliant, works perfectly in Node etc. You should submit as an answer. – david.pfx Jan 21 '19 at 06:09
  • 11
    @david.pfx There is a downside: readability. Especially when you compare it to solutions like `_.omit(obj, ['b', 'c'])`. – totymedli Sep 23 '19 at 02:49
  • 12
    @totymedli: Not by me. I'll take the syntactic form, part of standard ES6, over a magic function anytime, on readability grounds. – david.pfx Sep 24 '19 at 04:33
  • @HaroenViaene If the expression used in your eval is not something that the user COULD potentially uses for evil intention it's fine, you have to be aware of the potential risk however you are right> – vdegenne Jan 31 '20 at 16:47
  • A little bit too easy to hack… `omit({}, "}));alert('gotcha!')(({a")` – Brook Jordan Jul 21 '20 at 03:58
  • @BrookJordan why would you hack your own code ? If the part of the code is not used in a user interaction suite, it's fine. – vdegenne Aug 04 '20 at 20:09
  • 1
    That’s a big if. I don’t trust that any of my code in a shared codebase won’t have user generated text input at some point… I’m not sure I even trust that I won’t ever forget the internals of my code and put user content through it. – Brook Jordan Sep 10 '20 at 03:51
  • 3
    Why using a function ? why not simply do : ```const { b, c, ...clone } = obj``` ? – Simon Trichereau Aug 25 '21 at 08:25
  • 1
    @Simon Trichereau 's answer seems the easiest and most readable. – Jarrett Oct 26 '21 at 04:03
  • 5
    Using a function ensures that the variables `b` and `c` do not stay assigned (or reassigned) in the current scope. [A comment on the accepted answer](https://stackoverflow.com/questions/34698905/how-can-i-clone-a-javascript-object-except-for-one-key#comment65929164_34710102) mentioned that linters may even complain about that, if the variables are unused. – Daniel Avery Nov 28 '21 at 17:56
227
var clone = Object.assign({}, {a: 1, b: 2, c: 3});
delete clone.b;

or if you accept property to be undefined:

var clone = Object.assign({}, {a: 1, b: 2, c: 3}, {b: undefined});
madox2
  • 49,493
  • 17
  • 99
  • 99
  • 13
    Simply deleting the property is a clear and simple way to do it. – sshow Jul 06 '17 at 11:46
  • 46
    The caveat with delete is that it's not an immutable operation. – Javid Jamae Jul 25 '17 at 17:20
  • 3
    This is exactly what I was looking for, but a slightly more implemented in a slightly different way: var cake = {...currentCake, requestorId: undefined }; – abelito Apr 18 '19 at 22:39
  • 1
    @JavidJamae throwback to the times when everyone was obsessed about immutability of everything – Pawel Sep 08 '21 at 00:46
108

For those who can't use ES6, you can use lodash or underscore.

_.omit(x, 'b')

Or ramda.

R.omit('b', x)
Noel Llevares
  • 15,018
  • 3
  • 57
  • 81
  • 6
    wouldn't it be more logical to use [omit](https://lodash.com/docs/4.17.4#omit) here? `_.omit(x, 'b')` – tibalt Jun 22 '17 at 15:39
  • Thanks @tibalt. Updated the answer with it. – Noel Llevares Jun 23 '17 at 16:06
  • delete is more concise--using lodash, underscore or ramda is only relevant to projects that already use and know them, otherwise this is increasingly irrelevant in 2018 and beyond. – jimmont Sep 10 '18 at 23:07
  • 1
    @jimmont delete is already mentioned in other answers. There is no need for duplicate answers, don't you think? And of course, it is only relevant to those who already use lodash or ramda. And it is also only relevant to those stuck with ES5 and earlier as stated in this answer. – Noel Llevares Sep 10 '18 at 23:23
  • @dashmug my previous comment was a criticism of the approach (not of your answer) that should be noted when choosing to use the approach represented in this answer. I would want this information if I was reading through the answers and is the reason for adding my comment and mentioning `delete`. – jimmont Sep 19 '18 at 18:30
94

To add to Ilya Palkin's answer: you can even dynamically remove keys:

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

Source:

Paul Kögel
  • 1,801
  • 1
  • 13
  • 6
  • 2
    This is great, but is there a way to avoid the un-used var deletedKey? Not that it's causing any problems, but makes JSHint complain, and does seem odd since we really aren't using it. – Johnson Wong Jun 23 '17 at 00:41
  • 6
    @JohnsonWong How about using `_` which is allowed for a variable that you don't intend to use? – Ryan H. Aug 25 '17 at 23:40
  • ```var b = {a:44, b:7, c:1}; let {['a']:z, ...others} = b; console.log(z , others ); // logs: 44, {b:7, c:1}``` – jimmont Dec 18 '18 at 21:25
35

You can write a simple helper function for it. Lodash has a similar function with the same name: 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}

Also, note that it is faster than Object.assign and delete then: http://jsperf.com/omit-key

just-boris
  • 9,468
  • 5
  • 48
  • 84
  • 3
    I would instead filter the array of keys and then reduce without the if-statement: `Object.keys(obj).filter(key => key != omitKey).reduce((result, key) => ({...result, [key]: obj[key]}), {});` – wensveen Sep 25 '20 at 13:15
  • Using it, as it is faster than Object.assign – Lohith Dec 21 '20 at 11:17
  • @wensveen Spreading the result like that is incredibly slow, and even if you do it properly filter+reduce is still slower than just reduce, and both are slower than Object.assign+delete if the object has more than 20 properties: https://jsbench.me/x9l9ctn9wz/1 – Kael Watts-Deuchar Oct 17 '22 at 13:56
  • And reduce is even worse than Object.assign+delete if you're removing multiple keys, because then it has to check `omitKeys.includes(key)` on every iteration instead of just once at the end – Kael Watts-Deuchar Oct 17 '22 at 14:06
21

Here's an option for omitting dynamic keys that I believe has not been mentioned yet:

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

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

removeMe is aliased as removedKey and ignored. newObj becomes { 2: 2, 3: 3, 4: 4 }. Note that the removed key does not exist, the value was not just set to undefined.

goldins
  • 1,306
  • 1
  • 11
  • 14
18

Maybe something like this:

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

Is this good enough? Or can't c actually get copied?

clean_coding
  • 1,156
  • 1
  • 9
  • 14
15

Using Object Destructuring

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}
Ivan Nosov
  • 15,395
  • 2
  • 16
  • 14
  • 3
    I guess this solution is meant to prevent the 'Unused variable' warning in JSLint. Unfortunately, using `_` doesn't solve the issue for ESLint... – bert bruynooghe Jun 06 '19 at 17:13
  • The eslint rule you need is `"no-unused-vars": ["error", { "args": "all", "argsIgnorePattern": "^_" } ]`. – apostl3pol Dec 19 '21 at 22:32
6

Hey seems like you run in to reference issues when you're trying to copy an object then deleting a property. Somewhere you have to assign primitive variables so javascript makes a new value.

Simple trick (may be horrendous) I used was this

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"}
Chris Fust
  • 71
  • 1
  • 3
  • I actually kind of like it. Could do `JSON.parse(JSON.stringify(Object.assign({}, obj, { key2: undefined })));`. Don't even have to delete it, just needs a falsy value. – Chad Aug 23 '18 at 23:48
5

You also can use spread operator to do this

const source = { a: 1, b: 2, c: 3, z: 26 }
const copy = { ...source, ...{ b: undefined } } // { a: 1, c: 3, z: 26 }
Mickael M.
  • 197
  • 3
  • 4
  • 3
    Seems super nifty. This however keeps the key as undefined in `copy` – kano Sep 22 '18 at 15:04
  • so you could remove the undefined keys if there are the only ones to be in there – Victor Sep 27 '18 at 16:36
  • 5
    not sure why you did the extra spreading in the copy, `const copy = { ...source, b: undefined }` boils down to exactly the same. – bert bruynooghe Jun 06 '19 at 16:35
  • As mentioned before, `Object.keys(copy)` would still return `['a', 'b', 'c', 'z']` which is not always what you want. – kernel May 20 '21 at 14:49
5

What about this? I never found this patter around but I was just trying to exclude one or more properties without the need of creating an extra object. This seems to do the job but there are some side effects I'm not able to see. For sure is not very readable.

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

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

/**
a: {
   publicKey: 'public is safe',
   somethingElse: true,
}
*/
andreasonny83
  • 1,213
  • 11
  • 19
4

Lodash omit

let source = //{a: 1, b: 2, c: 3, ..., z:26}
let copySansProperty = _.omit(source, 'b');
// {a: 1, c: 3, ..., z:26}
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
4

I accomplished it this way, as an example from my Redux reducer:

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

In other words:

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
Jonathan Tuzman
  • 11,568
  • 18
  • 69
  • 129
  • Seems like a lot of extra work, compared to the accepted answer from 3 years ago (and both options rely on transpiling to for many browsers). – carpiediem May 08 '19 at 03:09
  • I have a similar use case (reducer) so I came up with a nice way that supports dynamic keys without mutation. Basically: `const { [removeMe]: removedKey, ...newObj } = obj;` - see my answer on this question. – goldins Oct 02 '19 at 17:33
4

The solutions above using structuring do suffer from the fact that you have an used variable, which might cause complaints from ESLint if you're using that.

So here are my solutions:

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

On most platforms (except IE unless using Babel), you could also do:

const src = { a: 1, b: 2 }
const result = Object.fromEntries(
  Object.entries(src).filter(k => k !== 'b'))
bert bruynooghe
  • 2,985
  • 1
  • 20
  • 18
4
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'));
  • 3
    While this code may provide a solution to the question, it's better to add context as to why/how it works. This can help future users learn, and apply that knowledge to their own code. You are also likely to have positive feedback from users in the form of upvotes, when the code is explained. – borchvm May 12 '20 at 05:43
4

I am using object destructuring here. I have separated the password into variables and the rest variables contain all object properties and values except the password. NOTE: rest is not fixed keyword here you can name it accordingly

const obj = {name:"john", password:"Abcds12@", id:"125455"}
const {password,...rest} = obj;
console.log(rest);
  • It would be nice to give a brief explanation of how this works / how it solves the problem, and how it's different than existing answers. – starball Dec 21 '22 at 07:35
  • I am using object destructuring here. I have separated the password into variables and the rest variables contain all object properties and values except the password. NOTE: rest is not fixed keyword here you can name it accordingly – ZAFAR HUSSAIN Dec 27 '22 at 17:00
  • Please always [edit] clarifications into your question post instead of hiding them in the comments. Comments are for _soliciting_ clarifications- not for providing them. – starball Dec 27 '22 at 19:52
3

If you're dealing with a huge variable, you don't want to copy it and then delete it, as this would be inefficient.

A simple for-loop with a hasOwnProperty check should work, and it is much more adaptable to future needs :

for(var key in someObject) {
        if(someObject.hasOwnProperty(key) && key != 'undesiredkey') {
                copyOfObject[key] = someObject[key];
        }
}
HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133
2

I don't know exactly what you want to use this for, so I'm not sure if this would work for you, but I just did the following and it worked for my use case:

const newObj ={...obj, [key]: undefined}
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Beto Shiver
  • 39
  • 1
  • 4
  • 2
    This way you will get object which has the `[key]` property with `value = undefined`. This is different than object not having the `[key]` property. E.g. `Object.keys()` will give you different results on these objects. – Rost Oct 27 '21 at 09:36
1

The delete keyword solution will throw a compilation error if you're using typescript, because it breaks the contract of the object you instantiated. And the ES6 spread operator solution (const {x, ...keys} = object) may throw an error depending on the linting configuration you're using on your project, since the x variable is not beign used. So I came up with this solution:

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

It solves the problem using the combination of Object.entries method (to get an array of key/value pairs of the original object) and the array methods filter and reduce. It looks verbose, but I think it's nice to have a one line chainable solution.

0

Here are my two cents, on Typescript, slightly derived from @Paul's answer and using reduce instead.

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']))
Oscar Nevarez
  • 994
  • 12
  • 24
0

I have one object named: options with some keys

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

I want to log all object excelp userPassword Property because Im testing something, I am using this code:

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

If you want to make it dynamic, just make a function and instead of explicitly putting userPassword you can place the value of the property you want to exclude

developer_009
  • 317
  • 3
  • 11
0

Clean and fast using lodash, With this solution, you are able to remove multiple keys and also without changing the original object. This is more extendable and more usable in different situations:

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 };
Kasir Barati
  • 606
  • 13
  • 24
-1

Here is a Typescript method to do that. Expects 2 arguments, the object and an array of strings containing keys to be removed:

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

You can use lodash library for this purpose (definitely if you need to work with lots of arrays/array of objects/objects in a project).

Using lodash deepclone function You can do:

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

First clones the whole object into new object and then delete the desired key from the cloned object so that the original one doesn't get affected.

MR_AMDEV
  • 1,712
  • 2
  • 21
  • 38