深入理解JavaScript中this的绑定机制与规则

作者:青柠时间:2026-10-23 05:40:18浏览:652

本文深入解析JavaScript中this关键字的绑定机制,澄清指向函数自身或词法作用域的常见误解。详细阐述默认绑定、隐式绑定、显式绑定(call/apply/bind)及new绑定的四种核心规则,并结合代码示例说明不同调用方式下this的具体指向,帮助开发者掌握this的动态绑定特性。

this关键字的常见误解

在JavaScript语言中,闭包、this关键字以及原型链是三个最易让人困惑的核心概念。尽管利用词法作用域等机制可以规避this带来的诸多陷阱,但为了深入理解语言本质并提升编程能力,我们需要打破舒适区,彻底厘清其工作原理。

一、常见对this关键字的误解

1、认为this指向函数自身

2、认为this指向函数的词法作用域

我们可以通过以下代码片段进行验证:


function test() {
test.a = 1;
this.a = 2;
console.log(test.a);
console.log(this.a);
console.log(test.a === this.a);
}

test();
console.dir(test);

在上述代码中,我们在函数test内部将test.a赋值为1,同时将this.a赋值为2。如果假设this指向函数自身,那么test.a与this.a应当相等,且值均为2。

接下来观察这段代码的实际运行结果:

this关键字的常见误解

this关键字的常见误解

从结果可以看出,scopes变量指向全局作用域window,此时this也指向window。尽管函数本身在JavaScript中也是对象,但this并不指向函数本身。

必须明确一点:this是在运行时进行绑定的,而非编写时确定。其上下文完全取决于函数调用时的具体条件。this的绑定与函数声明的位置无关,仅由函数的调用方式决定。

既然this是运行时绑定,我们能否通过强制绑定方法(如call、apply、bind)改变当前this的指向,使其不指向window而指向方法test本身?答案是肯定的,修改后的代码如下:


function test() {
 test.a = 1;
 this.a = 2;
 console.log(test.a);
 console.log(this.a);
 console.log(test.a === this.a);
 }
 
 test.call(test);
console.dir(test);

运行结果如下:

this关键字的常见误解

this关键字的常见误解

接下来探讨this是否指向函数的词法作用域,以下有一段具有代表性的代码:


function parent() {
 var a = 2;
 
 function child() {
 console.log(this.a)
 }
 child();
 
 }
parent();

若假设this指向函数的词法作用域,则child方法中的this.a应当存在。但实际执行结果如下:

this关键字的常见误解

实际上,在JavaScript内部,作用域确实类似于对象,其可见标识符均为该对象的属性。然而,这个作用域“对象”无法通过JavaScript代码直接访问,它存在于JavaScript引擎内部。因此,每当试图将this与词法作用域的查找机制混合使用时,务必意识到这是不可行的。

this的四种绑定规则

二、this的绑定规则

this的绑定规则主要可分为以下几类:

2.1 默认绑定

2.2 隐式绑定

2.3 显式绑定

2.4 new绑定

2.1 默认绑定

上述示例中this指向window,这些情况具有共同特征:函数引用不带任何修饰符进行调用。因此,只能应用默认绑定规则,无法适用其他规则。

2.2 隐式绑定

判断隐式绑定的首要规则是检查调用位置是否有上下文对象,即该函数是否被某个对象拥有或包含。例如:

this关键字的常见误解

此处的this指向对象obj。类似的情况包括DOM事件绑定,如document.getElementById('xxx').addEventListener('click', function(){xxx});在回调方法中,this指向被选择器选中的元素。这种情况下,可以简单理解为this指向调用方法点(.)前面的那个对象。

this关键字的常见误解

2.3 显式绑定

显式绑定在开发过程中应用广泛,借助这些方法可以直接改变当前方法的this指向,使JavaScript语言具备极高的灵活性。主要包含call、apply和bind三种方式,基本使用如下:


 function sum() {
 console.log(this.a + this.b);
 }
 var obj1 = {
 a: 1,
 b: 2
 };
 var test = sum.bind(obj1);
 sum.call(obj1); //3
sum.apply(obj1); //3
test(); //3

注意事项:

call和apply的第一个参数接受的是this对象。call在第二个参数之后可以接受以字符串形式传递的参数,而apply接受的是一个类数组或数组形式的参数列表。

当将null或undefined作为this的绑定对象传入call、apply或bind时,这些值在调用时会被忽略,实际应用的是默认绑定规则。

2.4 new绑定

JavaScript语言中的new操作符与其他面向对象语言中的new操作符存在差异,因为JavaScript中没有传统意义上的类概念。所有函数都可以使用new来调用,这种调用方式称为构造函数调用。在构造函数调用过程中,会自动执行以下操作:

1、创建(或构造)一个全新的对象

2、将该新对象执行[[Prototype]]连接

3、将该新对象绑定到函数调用时的this

4、如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象

构造函数是JavaScript中常用的一种设计模式,示例代码如下:


function Test(a, b) {
       this.a = a;
       this.b = b;
       this.add = function() {
         debugger;
        console.log(this.a + this.b);
       }
    }
    var cc = new Test(1, 2);
    cc.add();
    console.log(cc);

在new调用过程中,返回了一个新对象,并且该对象的this指向Test构造函数。

this关键字的常见误解

作者最新文章