Bk 3, CH 2 - this All Makes Sense Now

Nothing but Rules
Rule #1:- Default Binding

Default binding is the rule that applies when the other 3 rules don’t.
Consider the following code:-

Note that whenever a variable is declared in the global scope, it is the same with a global object, i.e window , property of the same name. There is a slight caveat I noticed while trying the code in different environments. First, if you tried the code in atom, the result is undefined and not 2 , even console.log( global.a ); results in undefined . Also, when you run the code with node, its the same result. As to why node gives undefined, check this link. Basically what is going on is that when this.a tries to find a in the global scope, it doesn’t find it because a is scoped to the module( make sure to check the link ) and not the global scope.

Rule #2:- Implicit Binding

Consider this code:-

First, obj is the context object because foo is being called on it i.e obj.foo(); Also, obj is also referred to as the owning object because obj references foo at the call site not just because foo is added as a reference property on obj or if foo is declared on obj . Note:- foo being declared on obj means instead of foo: foo , we have foo: function foo() {...} .

Let’s go over the previous point again. Whether foo is initially declared on obj or is added as a reference property, it is not enough to say that the function is owned or contained by obj

Implicitly Lost — This is when an implicitly bound function loses its this binding. Consider:-

Remember the this binding is determined by the call site. In the code above, the call site of foo is bar() . Make no mistake, the call site of foo isn’t obj.foo because foo was only referenced and not called with a () . Also, obj.foo is really the same thing as foo because obj.foo gives us a reference to the function foo . This code would help understand:-

Since bar(); , the call site of foo is a plain undecorated call, default binding applies.

Rule #3:- Explicit Binding

When you use a primitive value as the this value i.e

we can’t use this.a because the this binding is not pointing to an object.

Hard Binding
Take a look at this code:-

I got confused on how the argument 3 in bar( 3 ) was able to be passed to aruguments in foo.apply() . Let’s address how that. arguments is an object which contains its functions argument. Run this code to understand what that means.

Lets now take a look at the pattern using a reusable helper code:-

So in this code, why do we have to write return function() {...}; , why not just return fn.apply(..); . It is because of our arguments object. Remember the arguments object contains the arguments of its function. When var bar = bind(..) executes, return function(){..} refers to the code return fn.apply( obj, arguments ) . This implies that when bar is executed as a function, the arguments object would contain the arguments of bar which is 3.

Moving on to the built in utility, Function.prototype.bind for hard binding.

bind function the same way as our reusable helper from the previous code except bind is four letters. That means for the code foo.bind( obj ) , the this binding for foo is obj , and to pass in an argument for the function foo , we give pass it to bar() . IMO, it is important to understand how the reusable helper works so as not to have unnecessary issues when using bind in the future.

API call “contexts”
run this code:-

forEach takes an optional second parameter and uses it as the this binding for the function foo . Also, forEach takes parameters for foo inside the []

Rule #4 :- new Binding

I would like to highlight 2 things Kyle mentioned:-
1. “In JS, constructors are just functions that happen to be called with the new operator in front of them”
2. “There is no such thing as ‘constructor function’, but rather ‘construction calls of functions’ ”

Consider this code:-

when foo is called with new in front of it, a new object is created ( the object name would be bar)and this object is set as the this for the call of foo() then this.a = a; gives this new object its content which is a: 2 . Note that this.a is the same as bar.a

Everything in Order
1. new Binding
2. Explicit Binding
3. Implicit Binding
4. Default Binding

Testing whether implicit or explicit binding is more precedent:-

In obj1.foo.call(..) , the obj.foo part is implicit binding and the second part, foo.call() is explicit binding. If implicit binding is more precedent than explicit binding, the value of obj.foo.call( obj2 ) would have been 2 because of the implicit binding in the first part of the code, obj.foo . But explicit binding overrides it and 3 is logged out. Therefore explicit binding is more precedent than implicit binding.

Testing where new Binding’s precedence fits:-

The last 3 lines is where our focus is.
On the line var bar = new obj1.foo( 4 ); , obj.foo() is implicit binding and while adding the new keyword is new binding. If implicit binding was more precedent than new binding, console.log( obj1.a ); would have logged out 4, but implicit binding does not apply here because new binding takes precedence over implicit binding. new binding is shown by console.log( bar.a ); logging out 4.

Testing Hard binding with new Binding to see which is more precedent.

Remember bind works like our reusable helper. You might want to scroll back up to check to refresh your memory on how the reusable helper works.
Ok, so foo.bind( obj1 ) forces foo to be hard bound to obj1 and it returns a function so we can pass an argument for foo , bar( 2 ) , 2 is the argument indirectly passed to foo .

Now, bar is still hard bound to obj1 , however, in the line var baz = new bar( 3 ); , bar( 3 ) alone is hard binding while adding new is new binding. So we can see two kinds of binding, but only one is precedent. If hard binding was precedent, console.log( obj1.a ); would log out 3 because bar(3) passes 3 to foo with foo still being this binded to obj1 , but that doesn’t happen because new binding is more precedent. This is shown by console.log( baz.a ); logging out 3.

new bar( 3 ) creates a new object( remember bar contains code similar to the reusable helper ) and foo ‘s this is now bound to the new object,baz , rather than obj1 then foo gives this new object the value a: 3 ( through the line this.a = something ). So baz.a gives us 3. Therefore, even though bar was initially hard bound to obj1 , new binding overrides it because it is more precedent.

Softening Binding

Soft binding allows us “ to provide a different default for default binding (not global or undefined), while still leaving the function able to be manually this bound via implicit binding or explicit binding techniques.” ( Kyle Simpson)

foo.softBind( obj ) sets obj as the this binding if the this at call time is global or undefined.
Soft bind can be overridden with implicit or explicit binding . On line 13, foo.softBind( obj ) binds foo to obj and returns a function, like bind does, which is given to obj2.foo . obj2.foo(); which is implicit binding then overrides foo ‘s this binding and changes foo ‘s this to obj2 .
In fooOBJ.call( obj3 ); , fooOBJ ‘s this binding to obj (on line 9) is changed to obj3 as a result of explicit binding. Finally, setTimeout whose this binding is default binding falls back to soft binding which is binded to obj .

Questions are definitely welcomed =)