JavaScript中this指向的四种调用模式详解

作者:纸飞机时间:2026-10-27 19:56:26浏览:124

本文详细解析JavaScript中this关键字在不同执行上下文下的行为。通过方法调用、函数调用、构造器调用及apply调用四种模式,阐述this指向对象的判定规则。重点讲解方法调用中的延迟绑定机制,以及函数调用中this指向全局对象的设计特性与解决方案,帮助开发者准确掌握this的使用场景。

JavaScript this指向的四种调用模式详解

介绍 在面向对象编程中,this关键字扮演着核心角色,主要用于指示当前调用的对象。然而,在JavaScript中,this的行为表现复杂且差异显著,尤其受到不同执行上下文的强烈影响。

前文已提及,this作为执行上下文的一个属性,其取值逻辑必然与执行上下文紧密相关。

代码如下:

activeExecutionContext = {
VO: {...},
this: thisValue};

在JavaScript中,this的具体取值取决于函数的调用模式。JavaScript定义了四种调用模式:方法调用模式、函数调用模式、构造器调用模式以及apply调用模式。

方法调用模式与延迟绑定

调用模式 方法调用模式 当一个函数被存储为对象的属性时,该函数被称为方法。在方法调用模式下,this会被绑定到该方法所属的对象,即this指向调用该方法的对象。这一机制直观易懂:既然方法是对象的一部分,那么方法内部的this自然指向该对象。

代码如下:

var myObject = {
value : 0,
increment : function(inc) {
this.value += typeof inc === "number" ? inc : 1;
       }   
}   
myObject.increment();
console.log(myObject.value); //输出:1
myObject.increment(3);
console.log(myObject.value); //输出:4

由于可以通过this访问所属对象,因此可以调用或修改对象中的属性与方法。如前所述,this作为执行上下文的属性,仅在上下文创建时生成,这意味着this与对象的绑定发生在调用时刻,属于“延迟绑定”。这种延迟绑定机制使得this具有高度的复用性。

代码如下:

function showValue(){
console.log(this.value);
}
var a = { value : "a"};
var b = { value : "b"};
a.showValue = showValue;
b.showValue = showValue;
a.showValue(); //输出“a”
b.showValue(); //输出“b”

上述示例展示了函数的延迟绑定特性。

函数调用模式与全局对象绑定

函数调用模式 当函数并非作为对象的方法被调用时,即为函数调用。在函数调用模式下,this被绑定到全局对象(这是语言设计中的一个遗留问题)。

代码如下:

myObject.double = function(){
var that = this; //解决方法
var helper = function(){
console.log(that, ": ", that.value); //输出 Object {value: 4, increment: function, double: function} ": " 4
console.log(this, ": ", this.value); //输出 Window {top: Window, window: Window…} ": " undefined
    }
helper(); //以函数形式调用
}

按常理推断,this应指向函数所属对象,但由于语言设计原因,此处this指向全局对象。这种现象常令开发者感到困惑。不过,补救措施简单:如示例所示,使用that变量保存this的值。在helper函数内部调用that即可等效于使用this。至于为何函数调用模式下this指向全局对象,后续在分析引用类型时将详细探讨。

构造器调用模式

构造器调用模式 JavaScript基于原型继承,但其设计者希望它能像传统面向对象语言那样,通过new关键字和构造函数创建对象。这种设计有时显得略显尴尬,因为JavaScript的原型继承机制已足够强大,足以满足面向对象编程中的继承与多态需求。

言归正传,构造器调用模式相对简单。其核心是将一个函数作为构造器,并通过this声明需要共享的属性和方法。如下所示:

代码如下:

function Person(name, age){
this.name = name;
this.age = age;
this.say = function(){
console.log("name : %s, age : %n", this.name, this.age);
       }
}
var p1 = new Person("jink", 24);
p1.say(); //输出 name : jink, age : 24
var p2 = new Person("张三", 33);
p2.say();//输出 name : 张三, age : 33

从上述示例可清晰看出,this指向通过new关键字和构造函数创建的新对象。其原理在于:当使用new调用构造函数时,new运算符会调用函数内部的[[Construct]]方法,随后在对象创建完成后,再调用内部的[[Call]]方法。因此,对于相同的函数“Person”,this的值始终被设置为新创建的对象。

apply调用模式与手动绑定

apply调用模式 JavaScript中所有函数创建后,均自带apply和call两个方法。此处不赘述其具体用法,感兴趣者可自行查阅相关资料,其实并不复杂。通过这两个方法,我们可以手动指定this的值。虽然this在创建时不可修改,但在调用前手动设置则另当别论。这一机制允许对象调用任意方法,尽管功能实现效果取决于具体场景。

代码如下:

var programmer = {
name : "程序员",
hand : "灵活的双手",
programme : function(){
console.log(this.name+"用"+this.hand+"编写代码。");
    }
}
var pianist = {
 name : "钢琴家",
 hand : "灵活的双手",
 play : function(){
 console.log(this.name+"用"+this.hand+"弹奏动听的乐曲。");
 }
}
var player = {
 name : "运动员",
 foot : "矫健的双腿",
 run : function(){
 console.log(this.name+"用"+this.foot+"在赛场奔驰。");
 }
}
//循规蹈矩
programmer.programme(); //程序员用灵活的双手编写代码。
pianist.play(); //钢琴家用灵活的双手弹奏动听的乐曲。
player.run(); //运动员用矫健的双腿在赛场奔驰。
//异想天开
pianist.play.apply(programmer); //程序员用灵活的双手弹奏动听的乐曲。
player.run.apply(programmer); //程序员用undefined在赛场奔驰。 由于自身运动缺少,没有矫健的双腿

上述示例展示了apply方法的趣味性,其第一个参数即指定了方法执行时的this指向。这使得我们可以借用其他对象的方法,该技巧在各类框架中十分常见。

总结 关于this的讨论暂告一段落。相信读者已对不同情境下this的判定规则有了清晰认识。原计划进一步探讨引用对象,以阐述方法调用模式和函数调用模式中this取值的原理,但为避免篇幅过长,决定另辟一章专门分析引用对象这一概念。

作者最新文章