3
function multiMax(multi){
// Make an array of all but the first argument
var allButFirst = Array().slice.call( arguments, 1 );

// Find the largest number in that array of arguments
var largestAllButFirst = Math.max.apply( Math, allButFirst );

// Return the multiplied result
return multi * largestAllButFirst;
}
assert( multiMax(3, 1, 2, 3) == 9, "3*3=9 (First arg, by largest.)" );

from http://ejohn.org/apps/learn/#47

I have two questions for anyone.

  1. Why do we need to use Array().slice, but not Math().max.
  2. Why do we use Array().slice, and not Array.prototype.slice (I noticed that Array.prototype.slice will work, but I'm trying to understand why i would use one over the other, not just in this instance, but in any instance)

Thank you.

laserface
  • 449
  • 1
  • 4
  • 12

2 Answers2

2

Why do we need to use Array().slice, but not Math().max?

The reason that Array() is used in lieu of Array.prototype is because one is shorthand for the other in this specific instance.

Firstly: Array().slice.call(arguments, 1); has the same effect as [].slice.call(arguments, 1); as they both:

So to answer your first question, they do not "need" to use it there. It is used there simply due to preference. Array.prototype.slice.call(arguments, 1); or [].slice.call(arguments, 1); could be substituted and the function still work as expected.

As for Math.max.apply(Math, allButFirst);, Math is not a "class" like Array is in that the Math object cannot be instantiated (try it). Since it cannot be instantiated, it is not syntactically accessed or manipulated in the same manner as Array()/[].

That should answer your second question too.

As bmceldowney said, one does not usually call constructors without the new keyword. While legal, it irks me (personally) to see and I also do not believe it to be good practice in real life.

Xunnamius
  • 478
  • 1
  • 8
  • 16
  • Ok, I feel a little guilty here because just after I posted my question, I realized that I could just look up the difference between Math and Array, and you are correct. Math is not an object and has no prototype nor a constructor, so now I understand why the parens are not present. I'm still trying to wrap my head around prototypes and how to use them correctly. I feel like I understand them in reading (such as the example from John the Ninja's site), but whenever it comes to implementing them, I fail completely. Also, I did not realize you could use the literal [] that way. – laserface Mar 22 '13 at 07:06
1

My best shot:

  1. Array() will return an empty array instance whereas Array is just a constructor function. Array.slice doesn't work because the .slice method only exists on array instances, via their prototype. Math is not a constructor function, it's an object with a number of utility methods, one of which is max.

  2. I'm not sure there is a big difference between Array().slice and Array.prototype.slice other than concision, which the code you've posted seems to prize highly.

You don't usually see constructor functions being called without the 'new' keyword on purpose like that, I don't think it's very good practice. It's definitely clever code, which usually means not very maintainable.

bmceldowney
  • 2,307
  • 13
  • 19
  • Ok, this is a really interesting answer, because I think it brings me a bit closer to understanding prototypes.. Array.slice is a method that only exists on instances of new Array(). And in this example, new Array() is called without new, but still with access to the prototype method? How does that work exactly? – laserface Mar 22 '13 at 07:09
  • The implementation of Array (and probably the other built in wrapper classes) accounts for the caller forgetting to use he `new` keyword (http://stackoverflow.com/questions/1928342/javascript-using-constructor-without-operator-new). When an object is instantiated with the `new` keyword, it's prototype is set to it's constructor's prototype, hence the reason that both an Array instance and Array.prototype have a copy of the `slice` method, but the Array constructor function does not. I highly recommend picking up a copy of "Javascript: The Good Parts" for further explanation of this. – bmceldowney Mar 22 '13 at 14:58
  • Thank you again for your explanation. I have The Good Parts, and I've read through Secrets of the Javascript Ninja (partly written by John Resig). I thought I was there, but what you are saying about the Array constructor function has thrown me for a loop. If the Array constructor function doesn't have slice without being instantiated with the `new` keyword, I still don't get how this works. This example is taken from John Resig's book and his site, so I know he knows what he's doing by not using `new`. I'll just have to re-read The Good Parts. – laserface Mar 22 '13 at 15:39
  • Hmm. I may have cited the wrong book as I was looking back through The Good Parts and I can't find the relevant info. Basically, constructor functions can be written in such a way that they will still return something useful if invoked without the `new` keyword. This is true of the Array constructor function, but not generally true, it is up to the specific implementation (the SO question I linked to above has a decent explanation of this). John knows he can call Array() without the `new` keyword because he knows the spec. – bmceldowney Mar 22 '13 at 17:20
  • cool, thanks for that link. 'defined factory behavior' is not something i would have guessed at, but it makes sense, considering that many of the things you leave out in javascript, the language makes up for by adding it in for you... and I think these are the things that confuse me the most. But this link solves it for me. – laserface Mar 22 '13 at 18:49