25

Say, I have an object:

const user = {_id: 1234, firstName: 'John', lastName: 'Smith'}

I want to create another object without the _id key:

const newUser = {firstName: 'John', lastName: 'Smith'}

I am using this:

const newUser = Object.assign({}, {firstName: user.firstName, lastName: user.lastName})

Is there a better way to do this?

dpkwhan
  • 261
  • 1
  • 3
  • 4

6 Answers6

46

You can achieve it with a form of destructuring:

const user = { _id: 1234, firstName: 'John', lastName: 'Smith' };
const { _id, ...newUser } = user;
console.debug(newUser); 

However, at the time of writing this answer, the spread (...) syntax is still at the ECMAScript proposal stage (stage 3), so it may not be universally available in practice. You may use it with a "transpilation" layer such as Babel.

amn
  • 7,742
  • 8
  • 54
  • 82
madox2
  • 45,325
  • 15
  • 94
  • 95
5

Do it with Array#reduce method with Object.keys method.

const user = {
  _id: 1234,
  fistName: 'John',
  lastName: 'Smith'
};

var res = Object.keys(user).reduce(function(obj, k) {
  if (k != '_id') obj[k] = user[k];
  return obj;
}, {});

console.log(res);
Pranav C Balan
  • 110,383
  • 23
  • 155
  • 178
  • 2
    I wonder how this can be faster than the assignment that the OP makes. – trincot Nov 12 '16 at 12:33
  • 1
    @trincot - why not read the question, it says *"I want to create another object without the `_id` key"*, and then the OP shows the object that is the expected result, and goes on to say that he's using `Object.assign`, which is not direct assigment. – adeneo Nov 12 '16 at 14:37
  • Indeed, the `Object.assign` is of course superfluous in the OP's code. – trincot Nov 12 '16 at 14:53
  • @trincot : `Object.assign({}, {firstName: user.firstName, lastName: user.lastName})` is same as simple assigning `{firstName: user.firstName, lastName: user.lastName}`.. I think he want to copy all other property except `_id`.... in case he don't knows what are the property which have? – Pranav C Balan Nov 13 '16 at 13:31
  • @PranavCBalan, I understand that it is nice to have a generic solution, but the OP is not clear on that, as he seems to have a working solution that has hard-coded property names. For your first statement: I agree the outcome is the same, but with `Object.assign` two new objects are created (cf. the two object literals) instead of one, and so also the shallow copy is taken twice, not once. – trincot Nov 13 '16 at 13:37
  • @trincot `const newUser = {firstName: user.firstName, lastName: user.lastName}` is enough .... what he is expecting as result is not at all clear.... I think he need a generic solution for doing that... – Pranav C Balan Nov 13 '16 at 13:42
  • I agree that is enough (it is what [I answered](http://stackoverflow.com/a/40564052/5459839)), and I agree his expectations are not clear. We can only wait for the OP's return from his absence :) – trincot Nov 13 '16 at 13:51
3

You are taking a shallow copy twice: once with the object literal, and again with Object.assign. So just use the first of the two:

const newUser = {firstName: user.firstName, lastName: user.lastName};
trincot
  • 263,463
  • 30
  • 215
  • 251
1

The most efficient would most likely be a regular loop

const user = {_id: 1234, fistName: 'John', lastName: 'Smith'};
let   obj  = {}, key;

for (key in user) {
  if ( key !== '_id' ) obj[key] = user[key];
}

console.log(obj)
adeneo
  • 303,455
  • 27
  • 380
  • 377
  • 1
    How can a loop be faster than the direct assignment that the OP performs? – trincot Nov 12 '16 at 12:34
  • @trincot - `Object.assign` is not "direct assigment", it's an internal method that iterates, does some checks, and creates a new object, and it's not very efficient -> **https://jsperf.com/object-copy-efficiency-s**. Of course, if the op **can** use direct assigment, and can reference the keys directly, that's faster, but this just leaves out the `_id` property, like the other answers, and assumes one doesn't always want to use all the keys. – adeneo Nov 12 '16 at 14:31
  • Indeed, the `Object.assign` is of course superfluous in the OP's code. – trincot Nov 12 '16 at 14:54
  • @trincot - of course, as the properties are primitives, the `assign` call isn't needed at all, the OP is passing the object he wants to `Object.assign` and gets a copy of the exact same object, I just assumed the point was to leave out the `_id` property when creating the new object, not reference the other properties directly ? – adeneo Nov 12 '16 at 15:07
  • The question is indeed ambiguous. The OP writes *I am currently using this*, which would not be a possibility if the solution had to work for objects with other properties in his code as well. Not sure now. – trincot Nov 12 '16 at 15:21
1

This tiny function will select specific keys to either copy or exclude from copying. exclude take precedence:

function copy(obj, include=[], exclude=[]) {

  return Object.keys(obj).reduce((target, k) => {

    if (exclude.length) {
      if (exclude.indexOf(k) < 0) target[k] = obj[k];
    } else if (include.indexOf(k) > -1) target[k] = obj[k];
    return target;
  }, {});
}

// let's test it
const user = {
  _id: 1234,
  firstName: 'John',
  lastName: 'Smith'
};

// both will return the same result but have different uses.
console.log(
  'include only firstName and lastName:\n', 
  copy(user, ['firstName', 'lastName'])
);
console.log(
  'exclude _id:\n',
  copy(user, null, ['_id'])
);
SimoAmi
  • 1,198
  • 11
  • 13
0

Go through the object keys, put the wanted property keys in an array and use the Array.prototype.includes() to copy only these into the new object.

const account = {
  id: 123456,
  firstname: "John",
  lastname: "Doe",
  login: "john123",
  site_admin: false,
  blog: "https://opensource.dancingbear/",
  email: "john123@example.com",
  bio: "John ❤️ Open Source",
  created_at: "2001-01-01T01:30:18Z",
  updated_at: "2020-02-16T21:09:14Z"
};

function selectSomeProperties(account) {
return Object.keys(account).reduce(function(obj, k) {
    if (["id", "email", "created_at"].includes(k)) {
        obj[k] = account[k];
    }
    return obj;
  }, {});
}
const selectedProperties = selectSomeProperties(account);
console.log(JSON.stringify(selectedProperties))

The result:

{"id":123456,"email":"john123@example.com","created_at":"2001-01-01T01:30:18Z"}
s-hunter
  • 20,730
  • 14
  • 79
  • 113