Skip to content

Instantly share code, notes, and snippets.

@BIWhitfield
Created June 22, 2017 13:55
Show Gist options
  • Save BIWhitfield/2120c816f8b95314162a405e54d2ec56 to your computer and use it in GitHub Desktop.
Save BIWhitfield/2120c816f8b95314162a405e54d2ec56 to your computer and use it in GitHub Desktop.
Summary of the rules for the binding of `this` in JavaScript

1. Implicit Binding

  • Occurs automatically and implicitly when a function is called as a method of an object.
  • this points to the object to the left of the dot.
  • Most common and useful rule, ~80% of the cases.
let me = { name: "Mauro", sayName: sayName };

function sayName () {
  console.log("Hello, my name is", this.name)
}

me.sayName(); // Hello, my name is Mauro

2. Explicit Binding

  • The easiest to spot because it's explicitly written by a programmer.
  • Done with .call, .apply and .bind
let me = { name: "Mauro" };
function sayName () {
  console.log("Hello, my name is", this.name)
}

sayName.call(me) // Hello, my name is Mauro

var sayMauro = sayName.bind(me);
sayMauro(); // Hello, my name is Mauro
  • Can override implicit binding
let me = { name: "Mauro" };

function sayName () {
  console.log("Hello, my name is", this.name)
}

let boundSayName = sayName.bind(me);

let you = { name: "Ann", sayName: boundSayName };

you.sayName(); // Hello, my name is Mauro

3. New Binding

  • Inside a function that was called with the new operator.
  • this points to the new object being created.
function sayName () {
  console.log("Hello, my name is", this.name)
}

function Person (name) {
  // this = Object.create(Person.prototype)     <-- Happens under the hood
  this.name = name;
  // return this                                <-- Happens under the hood
}

Person.prototype.sayName = sayName;

var me = new Person("Mauro");
me.sayName();   // "Hello, my name is Mauro"

// This rule depends on the use of `new`.
// See what happens if we don't use it:
var me = Person("Mauro");
console.log(me);  // undefined, because `Person` doesn't return anything explicitly
me.sayName();     // TypeError, because me is `undefined` it cannot possibly have a `sayName` method

// we also leaked data into the global scope:
console.log(name);    // Mauro

This happens because when we called Person we didn't use the new operator. The new binding rule doesn't apply, nor the implicity and explicit ones. Therefore, the default rule applies and this points to the global object.

4. Global/Default Binding

  • Happens on "naked" function calls or when none of the other rules apply.
  • Not a useful rule, just a "catch all".
  • Depends on the environment in which we are running our program (browser, Node, etc.)
  • In the browser, this points to the window object.
  • If the function is in "strict mode", this points to undefined
function logThis () {
  console.log(this);
}

// Naked function call
logThis();    // global object

[1, 2, 3].forEach(logThis);
// You'd think that `this` would point to [1, 2, 3] but it doesn't
// It points to the global object because `forEach` calls `logThis` "nakedly" internally
// (see your implementation of _.each)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment