The Following rules from KYLE SIMPSON Book - You Don’t Know JS Book - this & Object Prototypes
- Default Binding
function foo() {
console.log(this.a)
}
var a = 5;
foo() // 5
because when you call foo - it's enter call stack - set the frame as global so this reference to global variable: window and the value of a is 5
- Implicit Binding
function foo(){
console.log(this.a)
}
var obj1 = {
a:5,
foo:foo
}
var obj2 = {
a:10,
foo:foo
}
obj1.foo() // 5
obj2.foo() // 10
function foo(){
console.log(this.a)
}
var obj1 = {
a:5,
foo:foo
}
var obj2 = {
a:10,
foo:foo
}
var bar = obj1.foo
var baz = obj2.foo
var a = 15;
bar() //15 in browser - undefined in node
baz() //15 in browser - undefined in node
Please read this to know why the result undefined in node
- Explicit binding
function foo(){
console.log(this.a)
}
var obj1 = {
a:5,
foo:foo
}
var obj2 = {
a:10,
foo:foo
}
var bar = obj1.foo
var baz = obj2.foo
var a = 15;
bar.call(obj1) // 5 - specify the value of this inside call
baz.call(obj2) // 10 - specify the value of this inside call
You can use call(thisArg,ArgsList) - apply(thisArgs,ArgsArray) - bind(thisArgs)
These topic form mdn to learn more about call , apply , bind
- new Binding
function foo(a){
this.a = a
}
var bar = new foo(3) //new convert bar to be an object an set a as a property and set 3 as it's value
console.log(bar.a) // 3
function foo(a,b) {
console.log( "a:" + a + ", b:" + b );
}
foo.apply( null, [2, 3] ); // a:2, b:3
// currying with `bind(..)`
var bar = foo.bind( null, 2 );
bar( 3 ); // a:2, b:3
However, there’s a slight hidden “danger” in always using null when you don’t care about the this binding. If you ever use that against a function call (for instance, a third-party library function that you don’t control), and that function does make a this reference, the default binding rule means it might inadvertently reference (or worse, mu‐ tate!) the global object ( window in the browser). Obviously, such a pitfall can lead to a variety of bugs that are very difficult to diagnose and track down.
Perhaps a somewhat “safer” practice is to pass a specifically set up object for this that is guaranteed not to be an object that can create problematic side effects in your program
const obj = Object.create(null)
function foo(a,b) {
console.log( "a:" + a + ", b:" + b );
}
// our DMZ empty object
var DMZ = Object.create( null );
// spreading out array as parameters
foo.apply( DMZ, [2, 3] ); // a:2, b:3
// currying with `bind(..)`
var bar = foo.bind( DMZ, 2 );
bar( 3 ); // a:2, b:3
ES6 arrow-functions use lexical scoping for this binding, which means they inherit the this binding (whatever it is) from its enclosing function call
function foo() {
const self = this
return ()=>{
console.log(self.a)
}
}
const obj = {a:4};
const bar = foo.call(obj);
bar() // 4
Determining the this binding for an executing function requires finding the direct call-site of that function. Once examined, four rules can be applied to the call-site, in this order of precedence:
- Called with new ? Use the newly constructed object.
- Called with call or apply (or bind )? Use the specified object.
- Called with a context object owning the call? Use that context object.
- Default: undefined in strict mode , global object otherwise.