21

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
  • 221
  • 1
  • 2
  • 4

6 Answers6

40

You can achieve it with destructuring and object rest properties:

const user = {_id: 1234, fistName: 'John', lastName: 'Smith'}
const {_id, ...rest} = user;
console.log(rest);

However rest/rpread properties are still an ecmascript's proposal (currently at stage 3). You can use it with transpilation layer such as babel.

s-hunter
  • 17,762
  • 11
  • 67
  • 105
madox2
  • 39,489
  • 13
  • 88
  • 91
4

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
  • 106,305
  • 21
  • 136
  • 157
  • 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
2

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
  • 211,288
  • 25
  • 175
  • 211
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
  • 293,187
  • 26
  • 361
  • 361
  • 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
0

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
  • 760
  • 9
  • 11
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
  • 17,762
  • 11
  • 67
  • 105