this的五种绑定规则：深入分析`new`绑定、`call`/`apply`/`bind`的显式绑定、隐式绑定和默认绑定。

admin
Wed, 24 Sep 2025 01:22:20 +0000
Javascript, call, new, 绑定

JavaScript 中 this 的五种绑定规则：深入剖析 大家好，今天我们来深入探讨 JavaScript 中 this 的五种绑定规则。this 是 JavaScript 中一个非常重要的概念，理解它的绑定机制对于编写健壮、可预测的代码至关重要。我们将逐一分析 new 绑定、call/apply/bind 的显式绑定、隐式绑定和默认绑定，并通过大量的代码示例来加深理解。 1. 默认绑定 (Default Binding) 默认绑定是 this 绑定中最基础的一种情况。当函数在非严格模式下独立调用时，this 会默认绑定到全局对象。在浏览器环境中，全局对象通常是 window；在 Node.js 环境中，全局对象是 global。 在严格模式下，默认绑定则会将 this 绑定到 undefined，以避免意外地修改全局对象。 代码示例： 非严格模式： function foo() { console.log(this.a); } var a = 2; foo(); // 输出: 2 (this 指向 window) function bar() { this.b = 3; } ba …

继续阅读“this的五种绑定规则：深入分析`new`绑定、`call`/`apply`/`bind`的显式绑定、隐式绑定和默认绑定。”

The post this的五种绑定规则：深入分析`new`绑定、`call`/`apply`/`bind`的显式绑定、隐式绑定和默认绑定。 first appeared on 智猿学院-前后端，数据库，人工智能，云计算等领域前沿技术讲座.

JavaScript 中 this 的五种绑定规则：深入剖析

大家好，今天我们来深入探讨 JavaScript 中 this 的五种绑定规则。this 是 JavaScript 中一个非常重要的概念，理解它的绑定机制对于编写健壮、可预测的代码至关重要。我们将逐一分析 new 绑定、call/apply/bind 的显式绑定、隐式绑定和默认绑定，并通过大量的代码示例来加深理解。

1. 默认绑定 (Default Binding)

默认绑定是 this 绑定中最基础的一种情况。当函数在非严格模式下独立调用时，this 会默认绑定到全局对象。在浏览器环境中，全局对象通常是 window；在 Node.js 环境中，全局对象是 global。

在严格模式下，默认绑定则会将 this 绑定到 undefined，以避免意外地修改全局对象。

代码示例：

非严格模式：

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

var a = 2;

foo(); // 输出: 2 (this 指向 window)

function bar() {
  this.b = 3;
}

bar();
console.log(window.b); // 输出: 3

严格模式：

"use strict";

function foo() {
  console.log(this); // 输出: undefined
}

foo();

function bar() {
  this.b = 3; // 报错：TypeError: Cannot set property 'b' of undefined
}

bar();

解释：

在非严格模式下，foo() 函数独立调用，this 默认绑定到 window，因此可以访问全局变量 a。bar() 函数也是如此，它实际上是在 window 对象上创建了一个属性 b。

在严格模式下，foo() 函数独立调用，this 绑定到 undefined，因此 console.log(this) 输出 undefined。bar() 函数试图在 undefined 上设置属性 b，导致 TypeError 错误。

总结：

默认绑定：函数独立调用时，this 默认绑定到全局对象（非严格模式）或 undefined（严格模式）。

严格模式下避免意外修改全局对象，因此将 this 设置为 undefined。

2. 隐式绑定 (Implicit Binding)

隐式绑定发生在函数作为对象的方法被调用时。在这种情况下，this 会绑定到调用该方法的对象。

代码示例：

var obj = {
  a: 2,
  foo: function() {
    console.log(this.a);
  }
};

obj.foo(); // 输出: 2 (this 指向 obj)

var obj2 = {
  a: 3,
  bar: function() {
    function baz() {
      console.log(this.a);
    }
    baz(); // 默认绑定
  }
};

obj2.bar(); // 输出: undefined (严格模式下会报错)

解释：

在第一个例子中，foo() 函数作为 obj 对象的方法被调用，因此 this 绑定到 obj，可以访问 obj.a。

在第二个例子中，bar() 函数也是 obj2 的方法，但 baz() 函数是在 bar() 内部独立调用的。因此，baz() 函数的 this 使用的是默认绑定，在非严格模式下指向 window，而 window 上没有 a 属性，所以输出 undefined。如果在严格模式下，baz() 中的 this 会是 undefined，访问 this.a 会抛出错误。

隐式丢失 (Implicit Loss):

隐式绑定有一个常见的问题，就是隐式丢失。当我们将对象的方法赋值给另一个变量，或者将方法作为回调函数传递时，可能会导致 this 绑定丢失，回到默认绑定。

代码示例：

var obj = {
  a: 2,
  foo: function() {
    console.log(this.a);
  }
};

var bar = obj.foo; // 将 foo 函数赋值给 bar
bar(); // 输出: undefined (非严格模式，this 指向 window)

setTimeout(obj.foo, 100); // 输出: undefined (非严格模式，this 指向 window)

解释：

在第一个例子中，bar 只是 obj.foo 函数的一个引用，它并没有和 obj 对象绑定。因此，当 bar() 被独立调用时，this 使用的是默认绑定，指向 window。

在 setTimeout 的例子中，setTimeout 接收一个函数作为参数，并在稍后执行。当 obj.foo 作为回调函数传递给 setTimeout 时，this 绑定也丢失了，setTimeout 内部会使用默认绑定。

解决隐式丢失的方法：

可以使用 bind 或者箭头函数来解决隐式丢失的问题。

使用 bind：

var obj = {
  a: 2,
  foo: function() {
    console.log(this.a);
  }
};

var bar = obj.foo.bind(obj);
bar(); // 输出: 2 (this 指向 obj)

setTimeout(obj.foo.bind(obj), 100); // 输出: 2 (this 指向 obj)

使用箭头函数：

var obj = {
  a: 2,
  foo: function() {
    setTimeout(() => {
      console.log(this.a);
    }, 100);
  }
};

obj.foo(); // 输出: 2 (this 指向 obj)

总结：

隐式绑定：函数作为对象的方法被调用时，this 绑定到调用该方法的对象。

隐式丢失：将对象的方法赋值给另一个变量，或者将方法作为回调函数传递时，可能导致 this 绑定丢失，回到默认绑定。

使用 bind 或箭头函数可以解决隐式丢失的问题。箭头函数没有自己的 this，它会捕获其所在上下文的 this 值。

3. 显式绑定 (Explicit Binding)

显式绑定允许我们明确地指定函数的 this 值。JavaScript 提供了 call、apply 和 bind 这三个方法来实现显式绑定。

call(thisArg, arg1, arg2, ...): 使用指定的 this 值和参数列表调用函数。

apply(thisArg, [arg1, arg2, ...]): 使用指定的 this 值和一个包含参数的数组来调用函数。

bind(thisArg, arg1, arg2, ...): 创建一个新的函数，当调用该函数时，它的 this 值会被设置为 thisArg，并且可以预先传入一些参数。bind 返回的是一个新函数，而不是直接调用函数。

代码示例：

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

var obj = {
  a: 2
};

foo.call(obj, 1, 2); // 输出: 5 (this 指向 obj)
foo.apply(obj, [1, 2]); // 输出: 5 (this 指向 obj)

var bar = foo.bind(obj, 1);
bar(2); // 输出: 5 (this 指向 obj)

解释：

call 和 apply 的区别在于参数的传递方式。call 接收参数列表，而 apply 接收一个包含参数的数组。

bind 方法会创建一个新的函数，该函数的 this 值被永久绑定到 bind 的第一个参数。bind 还可以预先传入一些参数，这些参数会在调用新函数时自动传入。

bind 的应用：

bind 的一个常见应用是在事件处理程序中，确保 this 指向正确的对象。

function Button(content) {
  this.content = content;
  this.showContent = function() {
    console.log(this.content);
  }
}

var myButton = new Button("Awesome Button!");
var btn = document.createElement('button');
btn.innerHTML = myButton.content;
btn.addEventListener('click', myButton.showContent.bind(myButton), false); // 使用 bind 绑定 this
document.body.appendChild(btn);

总结：

显式绑定：使用 call、apply 和 bind 明确地指定函数的 this 值。

call 和 apply 的区别在于参数的传递方式。

bind 创建一个新的函数，并将 this 值永久绑定到该函数。

bind 常用于事件处理程序中，确保 this 指向正确的对象。

4. new 绑定 (New Binding)

new 绑定发生在通过 new 关键字调用函数时。当使用 new 关键字调用函数时，会执行以下步骤：

1. 创建一个新的空对象。

2. 将新对象的 __proto__ 属性指向构造函数的 prototype 属性，从而建立原型链。

3. 将 this 绑定到这个新对象。

4. 执行构造函数中的代码。

5. 如果构造函数没有显式返回一个对象，则返回新创建的对象；否则，返回构造函数显式返回的对象。

代码示例：

function Foo(a) {
  this.a = a;
  console.log(this);
}

var bar = new Foo(2); // 输出: Foo {a: 2} (this 指向新创建的对象)
console.log(bar.a); // 输出: 2

解释：

当使用 new Foo(2) 调用 Foo 函数时，this 绑定到新创建的对象。因此，this.a = a 将 a 的值赋给新对象的 a 属性。

显式返回对象的情况：

function Foo(a) {
  this.a = a;
  return { b: 3 }; // 显式返回一个对象
}

var bar = new Foo(2);
console.log(bar.a); // 输出: undefined
console.log(bar.b); // 输出: 3

解释：

当构造函数显式返回一个对象时，new 关键字会忽略构造函数内部的 this 绑定，直接返回构造函数返回的对象。因此，bar 实际上指向的是 { b: 3 }，而不是通过 new 创建的对象。

总结：

new 绑定：使用 new 关键字调用函数时，this 绑定到新创建的对象。

如果构造函数没有显式返回一个对象，则返回新创建的对象；否则，返回构造函数显式返回的对象。

5. 优先级规则

当多种绑定规则同时存在时，this 的绑定会遵循一定的优先级。优先级从高到低依次为：

1. new 绑定

2. 显式绑定 (call/apply/bind)

3. 隐式绑定

4. 默认绑定

代码示例：

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

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

var obj2 = {
  a: 3
};

obj1.foo(5); // 隐式绑定
console.log(obj1.a); // 输出: 5

obj1.foo.call(obj2, 10); // 显式绑定
console.log(obj2.a); // 输出: 10

var bar = new obj1.foo(15); // new 绑定
console.log(obj1.a); // 5
console.log(bar.a); // 输出: 15

解释：

obj1.foo(5) 使用隐式绑定，this 指向 obj1，因此 obj1.a 被修改为 5。

obj1.foo.call(obj2, 10) 使用显式绑定，this 指向 obj2，因此 obj2.a 被修改为 10。

new obj1.foo(15) 使用 new 绑定，this 指向新创建的对象，因此新对象的 a 属性被设置为 15。obj1.a 仍然是 5，因为 new 绑定创建了一个新的对象。

总结：

优先级规则：new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定。

当多种绑定规则同时存在时，优先级最高的规则会生效。

总结：掌握 this 绑定，编写可预测的代码

通过今天的学习，我们深入了解了 JavaScript 中 this 的五种绑定规则：默认绑定、隐式绑定、显式绑定和 new 绑定。理解这些规则对于编写健壮、可预测的代码至关重要。记住，this 的绑定取决于函数的调用方式，而不是函数的定义位置。理解并掌握这些绑定规则，可以让你写出更加清晰、易于维护的 JavaScript 代码。