I try to extend JavaScript Math
. But one thing surprised me.
When I tried to extend it by prototype
Math.prototype.randomBetween = function (a, b) {
return Math.floor(Math.random() * (b - a + 1) + a);
};
In console I have error 'Cannot set property 'randomBetween' of undefined' ...
But if I asigne this function to Math.__proto__
Math.__proto__.randomBetween = function (a, b) {
return Math.floor(Math.random() * (b - a + 1) + a);
};
Then everything works fine.
Can anybody explain me why it works in this way? I appreciate any help.
Math
object is the prototype of the newMyMath
objectMyMath
has access to all functionality ofMath
MyMath
without manipulatingMath
this
to refer to theMath
functionalityThere is no Monkey Patching with this approach. This is the best way to extend JavScript
Math
. There is no need to repeat the explanations from the other answers.That's because there's
Math
is an object, not afunction
.In javascript, a
function
is the rough equivalent of a class in object oriented languages.prototype
is a special property which lets you add instance methods to this class1. When you want to extend that class, you useprototype
and it "just works".Now let's think about what
Math
is. You never create a math object, you just use it's methods. In fact, it doesn't make sense to create two differentMath
objects, becauseMath
always works the same! In other words, theMath
object in javascript is just a convenient way to group a bunch of pre-written math related functions together. It's like a dictionary of common math.Want to add something to that group? Just add a property to the collection! Here's two easy ways to do it.
Using the second way makes it a bit more obvious that it's a dictionary type collection, but they both do the same thing.
Math
isn't a constructor, so it doesn't haveprototype
property:Instead, just add your method to
Math
itself as an own property:Your approach with
__proto__
works because, sinceMath
is anObject
instance,Math.__proto__
isObject.prototype
.But then note you are adding
randomBetween
method to all objects, not only toMath
. This can be problematic, for example when iterating objects with afor...in
loop.To quote this answer:
The reason you can't assign to its prototype using
.prototype
is because theMath
object has already been created.Fortunately for us, we can assign new properties to the
Math
object by simply using:In your case, this would be: