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
isn't a constructor, so it doesn't have prototype
property:
new Math(); // TypeError: Math is not a constructor
Instead, just add your method to Math
itself as an own property:
Math.randomBetween = function (a, b) {
return Math.floor(Math.random() * (b - a + 1) + a);
};
Your approach with __proto__
works because, since Math
is an Object
instance, Math.__proto__
is Object.prototype
.
But then note you are adding randomBetween
method to all objects, not only to Math
. This can be problematic, for example when iterating objects with a for...in
loop.
That's because there's Math
is an object, not a function
.
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 use prototype
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 different Math
objects, because Math
always works the same! In other words, the Math
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.
Math.randomBetween = function() { ... }
Math["randomBetween"] = function() {... }
Using the second way makes it a bit more obvious that it's a dictionary type collection, but they both do the same thing.
To quote this answer:
Some JavaScript implementations allow direct access to the [[Prototype]] property, eg via a non-standard property named
__proto__
. In general, it's only possible to set an object's prototype during object creation: If you create a new object via new Func(), the object's [[Prototype]] property will be set to the object referenced by Func.prototype.
The reason you can't assign to its prototype using .prototype
is because the Math
object has already been created.
Fortunately for us, we can assign new properties to the Math
object by simply using:
Math.myFunc = function() { return true };
In your case, this would be:
Math.randomBetween = function(...) { ... };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With