JavaScript Binding Types Explained

January, 5th 2025 4 min read

Understanding how this works in JavaScript is one of the most important steps toward mastering the language. Unlike many programming languages where this behaves consistently, JavaScript binding rules depend entirely on how a function is called—not where it’s defined. This flexibility gives JavaScript enormous expressive power, but it can also confuse beginners and even experienced developers.

In this comprehensive 1000+ word guide, we will dive deep into all four binding types:

  • Default Binding
  • Implicit Binding
  • Explicit Binding
  • New Binding

Along the way, you’ll learn practical examples, common pitfalls, best practices, and real-world applications that strengthen your mental model of JavaScript function invocation.


Why Understanding this Matters

If you’ve ever seen unexpected values like:

js
console.log(this); // Window

or errors like:

plaintext
TypeError: Cannot read properties of undefined

you’ve already experienced issues related to binding.

Mastering this will help you:

  • Avoid bugs caused by incorrect context
  • Write cleaner object-oriented code
  • Understand how frameworks like React, Vue, and Node.js internals work
  • Use call, apply, and bind effectively
  • Work confidently with constructors and classes

1. Default Binding

Default binding applies when a function is called without any context.

Non-Strict Mode

In non‑strict mode, this refers to the global object:

  • window in browsers
  • global in Node.js

Example:

js
function showThis() {
  console.log(this);
}

showThis(); 
// Browser: Window
// Node.js: global object

Strict Mode

When "use strict" is enabled, default binding becomes safer:

js
"use strict";

function showStrict() {
  console.log(this);
}

showStrict(); 
// undefined

This behavior helps prevent accidental use of global variables.

Common Pitfall: Losing This Binding

js
const obj = {
  name: "Alice",
  getName() { return this.name; }
};

const fn = obj.getName;
fn();  
// undefined in strict mode
// window.name in non-strict mode

Why?
Because fn() uses default binding, not the object.


2. Implicit Binding

Implicit binding occurs when a function is invoked as a method of an object.

Example:

js
const user = {
  name: "Bob",
  greet() {
    console.log(`Hello, ${this.name}`);
  }
};

user.greet(); 
// "Hello, Bob"

In this case, the object to the left of the dot becomes the value of this.

Losing Implicit Binding

js
const greet = user.greet;
greet(); 
// this -> undefined

Because you extracted the method—it no longer has an owner.

Practical Use Case: Event Handlers

js
const button = {
  label: "Submit",
  click() {
    console.log(`${this.label} clicked`);
  }
};

document.addEventListener("click", button.click);
// this -> document, not button

Use bind() to fix:

js
document.addEventListener("click", button.click.bind(button));

3. Explicit Binding

Explicit binding lets you directly control this using:

  • call()
  • apply()
  • bind()

call()

Calls the function immediately with a specified this.

js
function sayName() { console.log(this.name); }

sayName.call({ name: "Charlie" });
// "Charlie"

apply()

Like call(), but accepts an array of arguments.

js
function introduce(greeting, punctuation) {
  console.log(`${greeting}, I'm ${this.name}${punctuation}`);
}

introduce.apply({ name: "Dana" }, ["Hello", "!"]);
// Hello, I'm Dana!

bind()

Returns a new function with permanently bound this.

js
const person = { name: "Eve" };

function sayHello() { console.log(this.name); }

const fn = sayHello.bind(person);

fn();  
// "Eve"

Bind is essential when passing callbacks into libraries or event handlers.


Real Use Case: setTimeout

js
const counter = {
  count: 0,
  increment() {
    console.log(++this.count);
  }
};

setTimeout(counter.increment, 1000);
// this -> window (not counter)

Fix with bind():

js
setTimeout(counter.increment.bind(counter), 1000);

4. New Binding (Constructor Binding)

When calling a function with new, JavaScript performs:

  1. Creates an empty object
  2. Sets this to that object
  3. Executes the function
  4. Returns the object (unless another object is explicitly returned)

Example:

js
function Person(name) {
  this.name = name;
}

const p = new Person("Frank");
console.log(p.name);
// "Frank"

If multiple binding rules apply, new binding wins over explicit binding:

js
function Test() { this.value = 1; }

const obj = {};
const fn = Test.bind(obj);

new fn();

console.log(obj.value); 
// undefined — new binding overrides explicit binding

5. Precedence of Binding Rules

When several binding types overlap, JavaScript follows this priority:

Binding Precedence (Highest → Lowest)

  1. new binding
  2. explicit binding (call, apply, bind)
  3. implicit binding
  4. default binding

Example:

js
function foo() { console.log(this.x); }

const obj1 = { x: 1, foo };
const obj2 = { x: 2 };

obj1.foo.call(obj2); 
// 2  (explicit beats implicit)

6. Arrow Functions and Lexical Binding

Arrow functions do not have their own this.
Instead, they inherit this from the surrounding scope.

Example:

js
const user = {
  name: "Grace",
  greet() {
    setTimeout(() => {
      console.log(this.name);
    }, 100);
  }
};

user.greet(); 
// "Grace"

Arrow functions are perfect for callbacks where you want to maintain context.

But they cannot be used as constructors:

js
const A = () => {};
new A(); 
// TypeError: A is not a constructor

7. Real Practical Examples

Example 1: Fixing Event Handler Binding

js
class Button {
  constructor(label) {
    this.label = label;
    this.click = this.click.bind(this);
  }
  click() {
    console.log(`Clicked ${this.label}`);
  }
}

const b = new Button("Save");
document.addEventListener("click", b.click);

Example 2: Methods Passed As Callbacks

js
const logger = {
  prefix: "[Log]",
  log(message) {
    console.log(this.prefix, message);
  }
};

["a", "b", "c"].forEach(logger.log.bind(logger));

Conclusion

Understanding JavaScript binding gives you full control over how functions are executed and how objects behave. Once you master:

  • default binding
  • implicit binding
  • explicit binding
  • new binding

…you’ll write more predictable, maintainable, and bug‑free code.

This knowledge is essential for:

  • mastering object-oriented JavaScript
  • writing class-based applications
  • working with frameworks
  • handling advanced async patterns
  • understanding library internals

With this guide and practice, you’ll never be confused by this again.