31

I've always wondered why Javascript has the global Math object instead of giving numbers their own methods. Is there a good reason for it?

Also are there any drawbacks (other than efficiency) to doing something like this?:

Number.prototype.round = function(){
    return Math.round(this);
};

Just to make clear, I understand that constants like π need somewhere and functions that are applied on more than one number like min/max. The question was mainly concerning methods which only effect a single number such as round, abs, sin, pow, etc.

8 Answers 8

26

The reason for the Math object is simple: "because Java does it". Not the best of reasons, but here we are. I guess things made more sense back then, before Douglas Crockford started his campaign to suppress half the language*. Originally you were "allowed", or meant, to do things like this:

with (Math) {
  var n = min( round(a) * round(b), sqrt(c) );
  var result = exp( n + d );
}

The drawback to extending Number.prototype is that someone else might do the same thing. Or worse, for example, define Number.prototype.round as a symmetrical rounding function.

If you are looking for ways to make your life easier, why stop there? Why not simply include Math functions as global functions?

var m = 'abs acos asin atan atan2 ceil cos exp floor log max min ' +
        'pow random round sin sqrt tan PI').split(' ');
for (var i=0,l=m.length; i<l; i++) {
  window[ m[i] ] = Math[ m[i] ];
}

This will drop all the math functions into the global scope, effectively allowing you to stop typing "Math." Ask yourself: Is there any real difference between extending Number and extending window with these functions?

* Before you flame me: The Crockford comment is not meant to be taken too seriously. I do agree with him that with is very dangerous in an implicit global environment.

Sign up to request clarification or add additional context in comments.

Comments

24

There is no drawback in extending Number.prototype other than confusing other people. What's the point? What is better in using value.round() instead of Math.round(value)?

There are several good reasons for the Math object:

  1. It works for non-numbers, too: Math.round("5") works whereas value.round() won't work when value is a string (for example, the value of a textbox)
  2. Some members of the Math object don't belong to a "primary" number value, like Math.min() or Math.max(). Or do you want to use it like a.max(b)?
  3. Other members are global and do not belong to a specialized number. Examples are constants like Math.PI or the function Math.random().

4 Comments

Good observations, +1. I'm wondering though, why Douglas Crockford said JavaScript made a mistake when borrowing the Math object from Java.
@Ferdinand: I was never planning on using anything like "a.max('5')". Some of the functions and constants belong in the Math object (I'll update my post to make that clear). The ones that are applied on the number alone is what I'm interested in. That you can use strings is a good point though.
There are also performance considerations -- value.anything requires boxing the value - eg. converting value into an object. (It is possible to avoid this occasionally, but not in any of your likely use cases)
I personally see point 1 above as a very helpful feature. Trying to round a string should throw an error. @olliej very good point about value boxing!
20

Try doing 123.round();

Your javascript console will throw a few hundred of errors to your eyes :P, nah ...

You can do:

Number.prototype.x then: (123).x(); but never 123.x();

3 Comments

I've always wondered why you couldn't do 123.method(). I know it's easier not to allow it because of floats, however I think ruby allows the syntax and it would make everything easier!
Yes, either 123..round() or (123).round() will work. 123..round() === 123.0.round()
until you started using framework liks Vue, than you'll see Error compiling template:
1

I think Math is more than set of Number methods. It's usage wider. Say, using NumberVariable.PI can be confusing. Same with random numbers generation.

Also I think extending number is OK, because it's the part of JS nature. Maybe someone will correct me if I am wrong here.

3 Comments

You can pretty much extend anything but the Array object. It's the Array object where extending get's annoying because you then can't do a simpel for..in loop (yes I know you can use a for() but that just looks so ugly.
@Pim Jager: you shouldn't be using for...in for arrays anyway - that's meant for objects. Which is why the real no-no is extending Object.prototype...
You can extend if your javascript version supports Object.defineProperty. There's the option enumerable:false
1

I believe calling it this way works as well, since Number's prototype functions work just like every other Object's prototype functions do:

5.5["round"]();
//should return 6

Comments

1

So, the conversation on whether its a good idea or not aside, you can do this fine.

You can do 123.x() but the interpreter for js is broken (as it doesn't interpret the dot as a message dispatch)

Weirdly, you can use 123 .x() (with a space between the number and the dot) instead, and it'll work.

123..also works but that's because you've effectively made a decimal and then dispatching to it

(typeof 123.) === 'number') // true

Try:

Number.prototype.times = function(other) { return this * other }; 3 .times(5);

in the console.

1 Comment

It's not "broken" when it's working the way it's intended.
0

My view on this is that if you do the proper checks as to not overwrite native functionality, name with understanding of native naming standards and it makes your code more readable and manageable, then make your code comfortable and convenient.

if (Number.prototype.round == null)
    Number.prototype.round = function() { return Math.round(this); }

AS for using this, because of the nature of javascript, I believe the best way to do this is by:

  • Wrapping the number in a variable instead of a simple static value (Most often the case)
    • nNum.round();
  • Wrapping the simple static value in parentheses :
    • (123).round();
  • Calling using square bracket notation
    • 123["round"].call();

Comments

0

You can do this

Number.prototype.round = function() {
    return Math.round(this.valueOf());
};

https://www.w3schools.com/jsref/jsref_prototype_num.asp

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.