Originally Posted by Dormilich
@rnd_me: could you explain why
var max=Math.max.apply.bind(Math.max, 0); requires a second parameter? (I tried various ones, it only matters that there is one)
a lot of folks, myself included, are confused at first by bind.
my big "aha" moment of understanding came by lining it up with the other two Function.prototype methods we all use and love; call() and apply().
turns out, bind() is EXACTLY like call() : it sets "this" with the first argument, and passes all other specified arguments as passed to the function you are calling it on. the only diff is that call() executes the function right there, whereas bind() stops short, returning the scoped function (the same as call would use) instead of the result.
let's throw bind() out, and examine the issue with the 1999 pieces.
you may have done something like this at some point:
you need to use "something" there for the same reason as zero (or something else) in my code.
apply's first argument is sucked into this.
if all that was passed was the array, max() would be called with the array as this
, and with no arguments
. apply() wants an array of arguments as arguments
 to turn into arguments
on the applied function.
the reason this works is because Math.max() doesn't look at this
, it only looks at it's arguments
, one number per argument:
Math.max.bind(0)([1,2,3]) //won't work
Math.max.call(0)([1,2,3]) //won't work
Math.max.call(0, [1,2,3]) // won't work
Math.max.call(0 ,1,2,3) // works
Math.max.apply(0, [1,2,3]) // works
Math.max.apply(999, [1,2,3]) // works
less obvious in my code is what's being bound.
it's not max(), it's apply().
check this out:
max([1,2,3]) // ===3
yeah, that's weird, but it works because apply() doesn't care what is in front or behind it. it's a generic. i guess you can think of it as being "loose"; it doesn't care what function, this
, or arguments
it's hooked up with. heh.
() generic steps this out for greater detail:
apply=Function.prototype.apply; //the template for "all applies"
max=apply.bind(Math.max, 0); //bind apply to max
max([1,2,3]); //call apply, bound to max, on argument
apply() wants two args: a new this and an array of other arguments.
bind wants 1+ arguments: this and others to pre-bake.
thus, we are essentially stacking the args for apply
onto the args for max
again, we can break it down to zoom in.
() method can be (jankily) written in userland using call
var code= "this.call(that," + args + ")" ;
"call code: "+code,
"this: "+ this,
return eval( code );
//go ahead and make it work side-by-side with the "real" fn.apply():
//try it as a function method:
Math.max.apply2(0, [1,2,3]); //works
//try it as a generic:
apply2.call(Math.max, 0, [1,2,3]); //works
//try it as a bound method to turn arguments into an array:
apply2.bind(Math.max, 0)([1,2,3]) // works
hmm, that a bit of typing i just did, doh!
im tryin to stop my mic-hogging.
you can "alert-ify" the Function.prototype.bind replacement on the MDC page i linked to if you want to step-through bind
() like the apply2
i made above.
does that help, or did i cloud the issue further?