4

So I got a little surprised by:

Object.assign({}, Math)

Which returned an empty object. I was doing this to set up my own math module, that I could extend with my own custom functionality, so I thought it would be convenient to do:

Object.assign({}, Math, { 
  sqrt: <my-sqrt-implementation>, 
  add: <my-add-implementation >,
})

But I was surprised to find that the math entries were not included, why is that? In my console I get:

Object.assign({}, Math)
> {}

What went wrong, and how can this be fixed?

user2662833
  • 1,005
  • 1
  • 10
  • 20

3 Answers3

5

The properties of Math are not enumerable. Object.assign will copy only enumerable and own properties:

The Object.assign() method only copies enumerable and own properties from a source object to a target object. It uses [[Get]] on the source and [[Set]] on the target, so it will invoke getters and setters. Therefore it assigns properties versus just copying or defining new properties. This may make it unsuitable for merging new properties into a prototype if the merge sources contain getters. For copying property definitions, including their enumerability, into prototypes Object.getOwnPropertyDescriptor() and Object.defineProperty() should be used instead.

Thus you should follow the suggestion, and use Object.getOwnPropertyNames(Math) to get a list of own property names, then Object.defineProperty() to assign them:

const props = Object.getOwnPropertyNames(Math)
const myMath = {}
props.forEach(prop => {
    Object.defineProperty(myMath, prop, Object.getOwnPropertyDescriptor(Math, prop))
})

myMath.sin(3.14)  // 0.00159265...

Of course, it is probably better to use prototypical inheritance (Object.create) here. I provide this code because it more closely matches the behavior of Object.assign, i.e. assignment.

Fengyang Wang
  • 11,901
  • 2
  • 38
  • 67
3

From : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign

The Object.assign() method only copies enumerable and own properties from a source object to a target object

Math properties aren't enumerable or own.

Example:

enter image description here

How can this be fixed?

Use Object.create e.g.

var MyMath = Object.create(Math);
MyMath.sqrt = function () {
};
basarat
  • 261,912
  • 58
  • 460
  • 511
  • 1
    I believe the Math properties are *own* (e.g., Math.hasOwnProperty('abs') is true). You are correct that they are not enumerable. – Fengyang Wang Oct 16 '18 at 23:41
  • If this is the case, then something like `var myMath = Object.assign(Object.create(Math), {...myMethods})` should work then. But its not working in my console. – user2662833 Oct 17 '18 at 03:00
0

The properties and methods under the Math object are set up as non-iterable. When Object.assign tries to copy them, they don't show up.

If you add your own property to the Math object, you'll see it is found and copied over.

Object.create, on the other hand, should do what you want.

// You shouldn't ever really do this.
Math.testProperty = true;
var myMath = Object.assign({}, Math);

console.log(myMath.testProperty);
Jeremy J Starcher
  • 23,369
  • 6
  • 54
  • 74