Skip to content

Instantly share code, notes, and snippets.

@NatashaKSS
Last active July 1, 2018 08:05
Show Gist options
  • Save NatashaKSS/e5bcf589f2357d211632c657788ca1d3 to your computer and use it in GitHub Desktop.
Save NatashaKSS/e5bcf589f2357d211632c657788ca1d3 to your computer and use it in GitHub Desktop.
My Notes for understanding JavaScript's "this" keyword binding behaviour

My Notes for understanding JavaScript's "this" keyword binding behaviour

adapted from Chapter 2 in "You Don't Know JS" here


Key Point: The call-site determines where this will reference during the execution of a function. There are essentially 4 rules governing how the call-site determines where this will point during the execution of a function.

Rule 1. Default Binding when not in 'strict' mode

function foo() {
  console.log(this.a);
}

var a = 2;

foo();

Rule 2. Implicit Binding

call-site uses obj context to reference the function. When there is a context object for a function reference, the implicit binding rule says that it's that object which should be used for the function call's this binding.

function foo() {
	console.log( this.a );
}

var obj = {
	a: 2,
	foo: foo
};

obj.foo(); // 2

Rule 3. Implicity Lost Binding & Explicit Binding

Implicity Lost Binding: Even though bar appears to be a reference to obj.foo, in fact, it's really just another reference to foo itself. Moreover, the call-site is what matters, and the call-site is bar(), which is a plain, un-decorated call and thus the default binding applies.

function foo() {
	console.log( this.a );
}

function doFoo(fn) {
	// `fn` is just another reference to `foo`

	fn(); // <-- call-site!
}

var obj = {
	a: 2,
	foo: foo
};

var a = "oops, global"; // `a` also property on global object

doFoo( obj.foo ); // "oops, global"

Explicit Binding: We create a function bar() which, internally, manually calls foo.call(obj), thereby forcibly invoking foo with obj binding for this. No matter how you later invoke the function bar, it will always manually invoke foo with obj. This binding is both explicit and strong.

function foo(something) {
	console.log( this.a, something );
	return this.a + something;
}

// simple `bind` helper
function bind(fn, obj) {
	return function() {
		return fn.apply( obj, arguments );
	};
}

var obj = {
	a: 2
};

var bar = bind( foo, obj );

var b = bar( 3 ); // 2 3
console.log( b ); // 5

Rule 4. new Binding

By calling foo(..) with new in front of it, we've constructed a new object and set that new object as the this for the call of foo(..)

function foo(a) {
	this.a = a;
}

var bar = new foo( 2 );
console.log( bar.a ); // 2

Order of precedence of these 4 rules:

4 > 3 > 2 > 1

i.e. new > explicit > implicit > default

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment