Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can any genius tell me what's going on in this small code? From Secrets of the JavaScript Ninja

Tags:

javascript

I'm barely starting JavaScript and I'm wondering if there are any geniuses out there that can help me understand this line by line?

1:  Function.prototype.bind = function(){
2:   var fn = this, 
3:      args = Array.prototype.slice.call(arguments), 
4:      object = args.shift();
5:   return function(){
6:   return fn.apply(object,
7:      args.concat(Array.prototype.slice.call(arguments)));
8:  };
9: };

I'm just beginner, but if you can teach me, then you're awesome. I know about prototypes, call, shift, apply a bit so you can skip the beginner parts (though I think you shouldn't so other who are barely getting into JS may learn how).

Notice: I know that there's a somewhat "similar code" asking a similar question here but I'm asking line by line explanation and they're not (not duplicate) (also, you can skip line 8 & 9) :)

like image 269
Jan Carlo Viray Avatar asked Feb 07 '12 09:02

Jan Carlo Viray


2 Answers

This is a partial implementation, in EcmaScript 3, of the EcmaScript 5 bind method which does partial application. It makes

myObject.method.bind(myObject, 1, 2)(3, 4)

is equivalent to

myObject.method(1, 2, 3, 4)

but its also more convenient because you can do

var m = myObject.method.bind(myObject, 1, 2);
m(3, 4);
m(5, 6);

instead of

myObject.method(1, 2, 3, 4);
myObject.method(1, 2, 5, 6);

Nit: The two are not entirely equivalent, because if the first call to myObject.method does this.method = somethingElse; then the bound method would still call the original.

To break it down:

Function.prototype.bind = function(){

Adds a method to the builtin function type.

var fn = this, 

Stores this which should be a Function in normal use so that it can be used inside a closure.

args = Array.prototype.slice.call(arguments), 

Creates an array containing the arguments to bind.

  object = args.shift();

Removes the first argument from args and stores it in object. This will be used as the this value for fn when it is applied later.

 return function(){

returns a function that acts as a partially applied method. This function when called

return fn.apply(object,

calls the function to the left of .bind passing the first argument to bind as this. apply is a special reflective method of functions which allows calling of a function with an array of arguments similar to *args or **kwargs in python, or ... in Java.

  args.concat(Array.prototype.slice.call(arguments)));

passes as arguments to fn, the arguments to bind followed by the argument to the closure.

like image 87
Mike Samuel Avatar answered Oct 19 '22 23:10

Mike Samuel


Let's say we have a function

function hi(a, b) { alert('hi! '+(a+b)); }

Define a function for every function (so you could use for example hi.bind())

1:  Function.prototype.bind = function(){

fn is this, hence the original function (in our example this = hi)

2:   var fn = this, 

arguments (the function's arguments) are not a normal array, so the following is a technique to convert it into an array which contains exactly the same elements as arguments

3:      args = Array.prototype.slice.call(arguments), 

shifts the args, returning the first one (which is the context with which you want to call the function)

4:      object = args.shift();

this function returns a new function

5:   return function(){

apply is a function that allows to to call a function with a given focus and arguments. hi(2,3) equals hi.apply(window, [2,3])

6:     return fn.apply(object,

The function will be called with the arguments to bind and any additional arguments you pass to the function we're in (which bind returns)

7:        args.concat(Array.prototype.slice.call(arguments)));
8:     };
9: };

So hi(2,3) equals (hi.bind(window, 2, 3))() equals (hi.bind(window, 2))(3)

like image 32
ori Avatar answered Oct 20 '22 01:10

ori