Step 3: what is the destination point of "this" for the variable "fn"?
The value of this contains a pointer to the current executable object of the function. Only function objects can be saved, therefore only things created based on new () or equivalent notation. This can be useful for passing a reference to an external object to an internal object created inside the specified external object.
Here's a minimal example:
function fn1() { var x = this; // x = fn1. this.u = 5; function fn2() { this.u = 10; console.log(this.u); // Prints the member of fn2. console.log(xu); // Prints the member of fn1. }; var W = new fn2(); } var V = new fn1();
The output should be:
10 5
First, an object of type fn1 , called V . It has a member variable u containing the value 5 . Then we create an object of type fn2 called W inside fn1 . It also has a member variable u , but here it contains the value 10 . If we wanted to print value of Vu inside W , we need a pointer to V Calling this.u inside W will output the value u (10), which we donβt want. Therefore, we define the variable x within the class fn1 , holding the this pointer for us. Now you can access the elements fn1 within fn2 .
Step 4
The first argument is associated with the object. You do not want to pass this to the function associated with it, which will violate its functionality, since it does not expect to add an additional argument to its regular list of arguments. So, the first argument should be removed.
Step 6: I really donβt understand how "!" Works.
!this is just a way of checking if this defined. If it is not, then the value will be true . Otherwise, since this would be an object (which evaluates to true when moving to a logical one), then this is false .
step 7: completely confused ...
Here, the original author checks to see if this is equal to either window or global . The note; In modern browsers, it is enough to check only window , but IE exists (as in non-browser javascript environments). So, a complete statement evaluates this thing:
If I am not called from within the object, or if I am called from the window or global object, then returning the softbind object was created using. Otherwise, return the object that I called from
Please note that this is exactly what the author of the original article wants. When a library function is called with this special binding, we can be sure that no matter what the library does; it cannot access the global context using the this variable. But it can access any other object, which allows you to interact with the library.
Step 9: can I write "curried.concat (arguments)" instead?
Curried contains all the arguments with which the original softbind function was softbind , except for the first argument. arguments , at this point is not equal to arguments in the previous call. Here he refers to the arguments with which the associated function is associated, and not to those with which it is associated. This line combines two sets of arguments, allowing you to provide default arguments. The trick used here is to combine arguments, for example. Suppose your function has default arguments [1,2,3,4] and you supply [5,6] :
[1,2,3,4].concat([5,6]) creates [1,2,3,4,5,6] .
Why not just team up and use a prototype? Arrays are passed by reference in javascript, so this will support Curried the same way, and concatenating arguments to a call. Equivalently, you can write this:
curried2 = curried.concat(arguments); return fn.apply( (.....) curried2);
Admittedly, brevity does not help the concept of this example. Just re-naming the arguments to be called and Curried (an extended mathematical term not related to explanation) as defaultArguments , and using a simple for loop for each argument would be much easier to understand if a little more verbose, I think the author wanted to be a fantasy.
Step 10: Why designate "fn.prototype" as the prototype of "bound.prototype"?
Go a little in the article to the part where the author talks about the default bind function and how it works: basically, the end result of replacing prototype back with the default prototype during a function call is that when the called softbind function softbind called using the operator new this , will be installed on its own, and not an associated default object. prototype will not work with a simple call to a related function.
It also allows inheritance, which means that creating objects for the softbind enabled function using prototype will not have this prototype canceled with softbind when it is bound. (This would make softbind incompatible with prototypes). Instead, both prototypes are used .
Also see this reddit post .
Warning word
We are expanding the language with new features. Features that are not absolutely necessary and are largely related to semantics. If you are just interested in learning a language, this is really too far away; you do not need special binding semantics. Worse, it can be confusing if this does not behave as you expect.
Simpler alternative
Enable strict mode. Now this by default will be undefined whenever it points to a global object. Prevents the problem that this complex code is trying to solve (usually leading to errors from functions trying to access member variables or undefined functions), and at the same time much easier to use, and at the same time it will complain about the syntax, which is correct regular javascript, but a bug in any normal use case. Also see the MDN article about this. He will catch many potential mistakes for you, instead of silently doing meaningless things.
Another alternative
bind tries to allow the "loss" of an object when passing its member function to another function, such as setTimeout . Another way to do this is to use an anonymous function. Instead of using (soft) binding, assuming that obj is an object containing the fn function, param is passed;
setTimeout(obj.fn(param), 500);
You can use:
setTimeout(function(param){obj.fn(param);}, 500);
This avoids the problem through a layer of indirection by passing an anonymous function. Also see this question .