Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the spread operator not copy over the prototype?

The following code does not appear to copy over an object's prototype.

const animalProto = {
 eat() {
  // function body
 },

 sleep() {
  // function body
 },
}

function animalCreator(proto, attributes) {
 return {...Object.create(proto), ...attributes}
}

const cat = animalCreator(animalProto, { name: 'garfield' })

cat.eat() // this is an error; function is not defined; it doesn't appear to link the prototype chain.

If I replace the spread with the following it works:

return Object.assign(Object.create(proto), attributes)

Essentially my question is why does Object.assign work but not the spread operator. Is there something Object.assign is doing that the spread operator is missing?

like image 990
technoY2K Avatar asked Jan 12 '19 22:01

technoY2K


2 Answers

See the docs:

It copies own enumerable properties from a provided object onto a new object.

"Own enumerable" means that properties on the prototype will not be included.

If you spread an object with inherited properties (such as an object immediately created with Object.create), none of those inherited properties will be present in the result.

Object.assign is slightly different - it assigns all properties to the right of the first to the first. It would be more similar to spread if you had passed an empty object as the first argument:

return Object.assign({}, Object.create(proto), attributes)

in which case nothing in proto would be reflected in the output.

const proto = { foo: 'bar' };
const result = Object.assign({}, Object.create(proto), { another: 'prop' });
console.log(result);
like image 143
CertainPerformance Avatar answered Oct 11 '22 13:10

CertainPerformance


Object.create() makes a new object that is prototype linked to the object passed to it. This means that the returned object doesn't get a copy of the parent's attributes, it just has a link to the parent prototype. The object spread only copies the objects own enumerable properties, which doesn't include those up the prototype chain.

const animalProto = {
 eat() {
  // function body
 },

 sleep() {
  // function body
 },
}

let o = Object.create(animalProto)
// o doesn't have it's own eat or sleep.
console.log(Object.getOwnPropertyNames(o))

console.log({...o}) // empty
like image 44
Mark Avatar answered Oct 11 '22 14:10

Mark