120

Is there a clean way to return a new object that omits certain properties that the original object contains without having to use something like lodash?

Mosh Feu
  • 28,354
  • 16
  • 88
  • 135
Aweb
  • 1,201
  • 2
  • 8
  • 6
  • Code? I would suggest create a new anonymous type, passing in what you want to keep – Edward Mar 25 '17 at 02:12
  • A similar question was asked here http://stackoverflow.com/questions/34698905/clone-a-js-object-except-for-one-key – gabesoft Mar 25 '17 at 02:22
  • 6
    Possible duplicate of [clone a js object except for one key](http://stackoverflow.com/questions/34698905/clone-a-js-object-except-for-one-key) – gyre Mar 25 '17 at 02:41

17 Answers17

219
const { bar, baz, ...qux } = foo

Now your object qux has all of the properties of foo except for bar and baz.

Miroslav Glamuzina
  • 4,472
  • 2
  • 19
  • 33
Craig Gehring
  • 3,067
  • 1
  • 9
  • 11
  • 4
    Keep in mind, this will not clone the object. Updating any values ion `qux` will update the values in `foo`. Javascript objects are passed by reference. – Miroslav Glamuzina Mar 12 '19 at 01:17
  • 28
    @MiroslavGlamuzina that's not correct. If you change a value in `qux` then `foo`'s value will not be updated. However, if the value of a property of `qux` is an object and you change something in that object, then the object referenced by the corresponding property of `foo` would also be changed. – Steven Oxley Jan 29 '20 at 05:51
  • Just a small note, in chrome (as of version 87.0.4280.141), this doesn't work with quoted property names. I don't know about other environments: `const { "bar", 'baz', ...qux } = foo` – Sledge Feb 04 '21 at 03:23
  • @Sledge some of your keys are quoted, that's probably why – surj Jul 31 '21 at 01:52
  • I don't think this is a great solution, because it has the side effect of creating new variables. If _any_ of the properties you're trying to omit _happen_ to match preexisting constants or variables, you'll get an error or unexpected behaviour `const x = "Anything"; const obj = { x: "Foo", y:"Bar"}; const {x, ...no_x} = obj;` – Lovethenakedgun Oct 19 '21 at 13:23
  • for picking 'string' fields you can use such syntax: `const { ["bar"]:bar, ["baz"]:bas, ...qux } = foo` If you have `const objKey = "bar";` you can usr such syntax: `const { [`${objKey}`]:bar, ["baz"]:bas, ...qux } = foo` – MadaShindeInai Oct 26 '22 at 16:42
52

In modern environments you can use this code snippet:

function omit(key, obj) {
  const { [key]: omitted, ...rest } = obj;
  return rest;
}
Eddie Cooro
  • 1,676
  • 14
  • 18
  • 4
    "modern environments" meaning if you're shipping un-transpiled code, this will work on 93% of browsers. See full compatibility at https://caniuse.com/mdn-javascript_operators_spread_spread_in_destructuring – Dawson B Feb 04 '21 at 19:18
  • who ships untranspiled code? – Erik Aronesty May 29 '23 at 18:21
42

If you know the list of the properties that you want preserved as well as omitted, the following "whitelisting" approach should work:

const exampleFilter = ({ keepMe, keepMeToo }) => ({ keepMe, keepMeToo })

console.log(
  exampleFilter({
    keepMe: 'keepMe',
    keepMeToo: 'keepMeToo',
    omitMe: 'omitMe',
    omitMeToo: 'omitMeToo'
  })
)
gyre
  • 16,369
  • 3
  • 37
  • 47
  • This has blown my mind, could you explain how it works? – rorymorris89 Mar 25 '17 at 02:25
  • It uses a combination of [parameter destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) and default object values (each key is mapped to the value held by the variable of the same name, e.g. `{ keepMe, keepMeToo }` is like `{ keepMe: keepMe, keepMeToo: keepMeToo }`. – gyre Mar 25 '17 at 02:30
  • 1
    Thanks! Cracking answer and upvoted for awesomeness. – rorymorris89 Mar 25 '17 at 02:37
  • Wow! Thank you for this! I was struggling with finding an answer, and then this came up! This solved my problem beautifully – J.H Sep 04 '20 at 22:45
  • 1
    Great anwser! Wonder if there is a way to avoid duplicating field names, couldn't find any. – Camilo Jan 30 '21 at 22:52
26

There's the blacklist package on npm which has a very flexible api.

Also a situational trick using the object rest-spread proposal (stage-3).

const {a, b, ...rest} = {a: 1, b: 2, c: 3, d: 4};
a // 1
b // 2
rest // {c: 3, d: 4}

This is often used in react components where you want to use a few properties and pass the rest as props to a <div {...props} /> or similar.

KyleMit
  • 30,350
  • 66
  • 462
  • 664
Brigand
  • 84,529
  • 20
  • 165
  • 173
19

A solution that hasn't been mentioned yet:

Omit single

o = {a: 5, b: 6, c: 7}
Object.fromEntries(Object.entries(o).filter(e => e[0] != 'b'))
// Object { a: 5, c: 7 }

Omit multiple

o = {a: 1, b: 2, c: 3, d: 4}
exclude = new Set(['a', 'b'])
Object.fromEntries(Object.entries(o).filter(e => !exclude.has(e[0])))
// Object { c: 3, d: 4 }

The Set above is used because it leads to linearithmic complexity even if the number of elements in exclude is in the same asymptotic equivalence class as the number of elements in o.

Grant Zvolsky
  • 483
  • 5
  • 6
12

Omit and array of keys, using ES7 w/ recursion.

function omit(keys, obj) {
  if (!keys.length) return obj
  const { [keys.pop()]: omitted, ...rest } = obj;
  return omit(keys, rest);
}

This builds on top of @Eddie Cooro answer.

will Farrell
  • 1,733
  • 1
  • 16
  • 21
  • 5
    non-recursive version: ` function omit(keys, obj) { return keys.reduce((a, e) => { const { [e]: omit, ...rest } = a; return rest; }, obj) } ` – Magical Gordon Aug 05 '20 at 19:33
  • 2
    typescript non recursive version: `export function omitObjectKeys( keys: string[], obj: T, ): Partial { return (keys as any).reduce((a: Partial, e: keyof T) => { const { [e]: omitted, ...rest } = a; return rest; }, obj); }` – Bogdan Surai Jun 03 '21 at 14:36
  • This is unnecessarily inefficient (with practical implications), since it copies the entire object for every key that needs to be omitted. – Ry- Aug 23 '22 at 20:23
7

You can use Object.assign(), delete

var not = ["a", "b"]; // properties to delete from obj object
var o = Object.assign({}, obj);
for (let n of not) delete o[n];

Alternatively

var props = ["c", "d"];
let o = Object.assign({}, ...props.map(prop => ({[prop]:obj[prop]})));
guest271314
  • 1
  • 15
  • 104
  • 177
6

Sure, why not something like:

var original = {
  name: 'Rory',
  state: 'Bored',
  age: '27'
};

var copied = Object.assign({}, original);
delete copied.age;

console.log(copied);

https://jsfiddle.net/4nL08zk4/

rorymorris89
  • 1,144
  • 7
  • 14
6

If you already use lodash, you may also do omit(obj, ["properties", "to", "omit"]) to get a new Object without the properties provided in the array.

Mitsakos
  • 214
  • 1
  • 6
  • 9
6

Building on other answers: if there's not a need for reusability or abstraction this will remove blacklisted properties inline with an IIFE.

(
  ({
    // Properties to remove from `someObject`.
    omitMe,
    omitMeToo,
    // The rest of `someObject`, to keep.
    ...keep
  }) => keep
)(someObject)

Example

const someObject = {
  keepMe: 'keepMe',
  keepMeToo: 'keepMeToo',
  omitMe: 'omitMe',
  omitMeToo: 'omitMeToo',
};

console.log(
  (
    ({
      omitMe,
      omitMeToo,
      ...keep
    }) => keep
  )(someObject)
);
kentr
  • 969
  • 1
  • 11
  • 21
1

No answer seemed to allow nested path specifications using dot notation. Here's a solution for that:

const omit = (obj, keys) => {
  if (!keys.length) return obj;
  const key = keys.pop();
  const parts = key.split(".");
  if (parts.length > 1) {
    const { [parts[0]]: todo, ...rest } = obj;
    return {
      ...omit(rest, keys),
      [parts[0]]: omit(todo, [parts[1]]),
    };
  }
  const { [key]: omitted, ...rest } = obj;
  return omit(rest, keys);
};
    
var obj = {
  a: 1,
  b: 2,
  c: 3,
  d: {
    c: 3,
    e: 5
  }
};
console.log(omit(obj, ['b', 'd.c']));
Mike Crowe
  • 2,203
  • 3
  • 22
  • 37
0
function omitKeys(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; 
    }
Andrés Andrade
  • 2,213
  • 2
  • 18
  • 23
0

var obj = {
  a: 1,
  b: 2,
  c: 3,
  d: {
    c: 3,
    e: 5
  }
};

Object.extract = function(obj, keys, exclude) {
  var clone = Object.assign({}, obj);
  if (keys && (keys instanceof Array)) {
    for (var k in clone) {
      var hasKey = keys.indexOf(k) >= 0;
      if ((!hasKey && !exclude) || (hasKey && exclude)) {
        delete clone[k];
      }
    }
  }
  return clone;
};

console.log('Extract specified keys: \n-----------------------');
var clone1 = Object.extract(obj, ['a', 'd']);
console.log(clone1);
console.log('Exclude specified keys: \n-----------------------');
var clone2 = Object.extract(obj, ['a', 'd'], true);
console.log(clone2);
ajai Jothi
  • 2,284
  • 1
  • 8
  • 16
0
const data = { name : 'Micheal', passowrd : 'password', age: '44'}
const dataClean = data.toObject();
delete dataClean.password;
console.log(dataClean);
0

Taking Grant Zvolsky's answer and turning it into functions

function omit(obj, key) {
  return Object.fromEntries(Object.entries(obj).filter(e => e[0] != key))
}
/** Omits multiple keys. The exclude parameter is a Set of keys to exclude **/
function omitSet(obj, exclude) {
  return Object.fromEntries(
    Object.entries(obj).filter((e) => !exclude.has(e[0]))
  );
}

o = {a: 1, b: 2, c: 3, d: 4}
exclude = new Set(['a', 'b'])
console.log(omitSet(o, exclude));
// Object { c: 3, d: 4 }

Or in Typescript:

function omitSet(obj: object, exclude: Set<string>) {
  return Object.fromEntries(
    Object.entries(obj).filter((e) => !exclude.has(e[0]))
  );
}
Jeremy Bernier
  • 1,746
  • 1
  • 17
  • 17
-1

One solution, I'm sure many others exist.

const testObj = {
    prop1: 'value1',
    prop2: 'value2',
    prop3: 'value3'
};

const removeProps = (...propsToFilter) => obj => {
   return Object.keys(obj)
   .filter(key => !propsToFilter.includes(key))
   .reduce((newObj, key) => {
       newObj[key] = obj[key];
       return newObj;
   }, {});
};


console.log(removeProps('prop3')(testObj));
console.log(removeProps('prop1', 'prop2')(testObj));

Edit: I always forget about delete...

const testObj = {
    prop1: 'value1',
    prop2: 'value2',
    prop3: 'value3'
};

const removeProps = (...propsToFilter) => obj => {
   const newObj = Object.assign({}, obj);
   propsToFilter.forEach(key => delete newObj[key]);
   return newObj;
};


console.log(removeProps('prop3')(testObj));
console.log(removeProps('prop1', 'prop2')(testObj));
Alex Young
  • 4,009
  • 1
  • 16
  • 34
-2

I saw this question and I wanted to remove 1 specific key, not a full method, so here's my suggestion:

const originalObj = {wantedKey: 111, anotherWantedKey: 222, unwantedKey: 1010};
const cleanedObj = Object.assign(originalObj, {unwantedKey: undefined});
Leyb
  • 1
  • 5
  • It does not work this way: if you have the value in the source - it overwrites the corresponding value in the target. In the given case, unwantedKey will be copied and be 1010. – Alexander Dec 01 '20 at 14:52