423

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,090
  • 1
  • 17
  • 36
fox
  • 11,694
  • 20
  • 47
  • 76

26 Answers26

588

If you use Babel you can use the following syntax to copy property b from x into variable b and then copy rest of properties into variable y:

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

and 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"]);
ericgio
  • 2,121
  • 2
  • 18
  • 37
Ilya Palkin
  • 11,463
  • 2
  • 21
  • 35
  • 75
    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
  • 23
    @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
  • 1
    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
  • To avoid "Unused variable" warning and still using the spread operator you can do: `let y = {...x}; delete y.b;` – jWang1 Mar 30 '20 at 13:30
  • 1
    I did a `let { b: _b, ...y } = x;` to skip the "Unused variable" warning. – Waseem May 20 '21 at 00:54
174
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
  • 39,489
  • 13
  • 88
  • 91
97

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
  • 8,291
  • 10
  • 65
  • 90
  • 11
    Instead of wrapping in array and `map` you can do: `(({b, c, ...others}) => ({...others}))(obj)` – bucabay Dec 22 '18 at 10:51
  • @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
  • 3
    @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
  • 5
    @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
  • 3
    Nobody is commenting on the `eval` here? – Haroen Viaene Jan 31 '20 at 16:17
  • @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
  • I removed the general purpose example, check the edit history if you are interested. Because `eval` is not recommended in some case I don't want to mislead new comers into using it. – vdegenne Apr 16 '21 at 21:41
83

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

_.omit(x, 'b')

Or ramda.

R.omit('b', x)
Noel Llevares
  • 11,823
  • 2
  • 41
  • 72
  • 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
82

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,441
  • 1
  • 11
  • 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
28

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
  • 8,201
  • 5
  • 41
  • 77
  • 1
    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
16

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,056
  • 1
  • 8
  • 14
13

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
  • 11,641
  • 2
  • 14
  • 12
  • 2
    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
13

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
  • 947
  • 7
  • 14
9

How about this:

let clone = Object.assign({}, value);
delete clone.unwantedKey;
Lars Juel Jensen
  • 1,403
  • 1
  • 20
  • 28
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
4

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.
  • 179
  • 2
  • 4
  • 2
    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
  • 2
    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
4

I recently did it this very simple way:

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

just using spread operator to separate the unwanted property:

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

...and object.assign to take only the 'rest' part:

const newObj = Object.assign({}, {...rest});
Pepdbm 7
  • 131
  • 1
  • 9
  • 4
    `rest` is already a new object- you don't need the last line. Plus, this is identical to the accepted solution. – carpiediem May 08 '19 at 03:12
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,761
  • 1
  • 18
  • 18
3

Lodash omit

let source = //{a: 1, b: 2, c: 3, ..., z:26}
let copySansProperty = _.omit(source, 'b');
// {a: 1, c: 3, ..., z:26}
OscarRyz
  • 184,433
  • 106
  • 369
  • 548
3

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,108
  • 9
  • 19
3
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
2

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
  • 10,963
  • 6
  • 53
  • 100
2

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
  • 6,575
  • 7
  • 33
  • 77
  • 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
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
  • 30,672
  • 69
  • 32
  • 52
Beto Shiver
  • 31
  • 1
  • 2
1

If you use Ramda you can use its omit and clone functions to make a deep clone of your object and omit the unnecessary fields.

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

I had an object that I wanted to remove after utilizing its method. This is what worked for me.


/* 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 :)


Good Luck :)

Aakash
  • 14,077
  • 4
  • 77
  • 63
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
  • 835
  • 10
  • 22
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

crazyX
  • 113
  • 1
  • 8
0

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.

-1

Using loadash 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
  • 934
  • 1
  • 12
  • 23