本文深入解析JavaScript中this关键字的绑定机制。通过决策树图解,详细阐述作为对象方法、普通函数、构造函数以及使用apply/call调用时this的不同指向。结合具体代码案例,说明非严格模式下this指向全局对象或当前对象的判断逻辑,帮助开发者掌握这一核心概念。
JavaScript this 关键字概述
JavaScript 是一门支持函数式编程、闭包及基于原型继承等高级特性的脚本语言。尽管其入门门槛看似较低,但随着开发深入,许多基础概念显得晦涩难懂。其中,this 关键字因在不同场景下指向不同对象而常令人困惑。业界有一种观点认为,只有透彻理解 this 的机制,才算真正跨入 JavaScript 开发的门槛。与 Java、C# 等主流面向对象语言在编译期绑定 this 指向当前对象不同,JavaScript 中的 this 是在运行期动态绑定的,这正是其含义多变且复杂的根本原因。
this 指向与函数调用方式
得益于运行期绑定的特性,JavaScript 中的 this 可能指向全局对象、当前对象或任意其他对象,具体取决于函数的调用方式。JavaScript 主要包含四种函数调用模式:作为对象方法调用、作为普通函数调用、作为构造函数调用,以及通过 apply 或 call 方法调用。俗话说“一图胜千言”,为了更直观地展示 this 的指向逻辑,下文将通过一张决策图进行解析。

上图被称为“JavaScript this 决策树”(适用于非严格模式)。下面通过具体示例演示如何利用该决策树判断 this 的指向。
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
this.x = this.x + x;
this.y = this.y + y;
}
};
//决策树解释:point.moveTo(1,1)函数不是new进行调用,进入否决策,
//是用dot(.)进行调用,则指向.moveTo之前的调用对象,即point
point.moveTo(1,1); //this 绑定到当前对象,即point对象
对象方法调用中的 this 指向
以 point.moveTo() 函数为例,其在“JavaScript this 决策树”中的判定路径如下:
1)判断 point.moveTo 函数是否通过 new 关键字调用?显然不是,因此进入“否”分支,继续判断函数是否通过点运算符(.)调用;
2)point.moveTo 函数确实是通过点运算符(.)调用的,因此进入“是”分支,此时 this 指向点运算符左侧的对象,即 point;
point.moveTo 函数 this 指向的图解分析如下图所示:
再举一个代码示例:
function func(x) {
this.x = x;
}
func(5); //this是全局对象window,x为全局变量
//决策树解析:func()函数是用new进行调用的么?为否,进入func()函数是用dot进行调用的么?为否,则 this指向全局对象window
x;//x => 5
普通函数调用中的 this 指向
func() 函数在“JavaScript this 决策树”中的判定过程如下:
1)判断 func(5) 是否通过 new 关键字调用?显然不是,进入“否”分支,继续判断函数是否通过点运算符(.)调用;
2)func(5) 并非通过点运算符调用,因此进入“否”分支,此时 this 指向全局变量 window,故 this.x 实际上等同于 window.x;
func 函数 this 指向的图解分析如下图所示:

针对作为普通函数直接调用的情况,下面看一个更复杂的例子:
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
// 内部函数
var moveX = function(x) {
this.x = x;//this 指向什么?window
};
// 内部函数
var moveY = function(y) {
this.y = y;//this 指向什么?window
};
moveX(x);
moveY(y);
}
};
point.moveTo(1,1);
point.x; //=>0
point.y; //=>0
x; //=>1
y; //=>1
内部函数中的 this 指向
point.moveTo(1,1) 函数内部实际调用了 moveX() 和 moveY() 函数。对于 moveX() 函数内部的 this,其在“JavaScript this 决策树”中的判定过程如下:
1)判断 moveX(1) 是否通过 new 关键字调用?显然不是,进入“否”分支,继续判断函数是否通过点运算符(.)调用;
2)moveX(1) 并非通过点运算符调用,因此进入“否”分支,此时 this 指向全局变量 window,故 this.x 实际上等同于 window.x;
接下来看作为构造函数调用的示例:
function Point(x,y){
this.x = x; // this ?
this.y = y; // this ?
}
var np=new Point(1,1);
np.x;//1
var p=Point(2,2);
p.x;//error, p是一个空对象undefined
window.x;//2
构造函数调用中的 this 指向
在语句 var np=new Point(1,1) 中,Point(1,1) 函数的 this 在“JavaScript this 决策树”中的判定过程如下:
1)判断 var np=new Point(1,1) 是否通过 new 关键字调用?显然是,因此进入“是”分支,此时 this 指向新创建的实例 np;
2)因此 this.x=1 等价于 np.x=1;
再看 var p= Point(2,2) 中 Point(2,2) 函数的 this 在“JavaScript this 决策树”中的判定过程:
1)判断 var p= Point(2,2) 是否通过 new 关键字调用?显然不是,进入“否”分支,继续判断函数是否通过点运算符(.)调用;
2)Point(2,2) 并非通过点运算符调用,判定为否,进入“否”分支,此时 this 指向全局变量 window,故 this.x 实际上等同于 window.x;
3)执行 this.x=2 即 window.x=2。
最后,查看通过 call 和 apply 方法调用的示例:
function Point(x, y){
this.x = x;
this.y = y;
this.moveTo = function(x, y){
this.x = x;
this.y = y;
}
}
var p1 = new Point(0, 0);
var p2 = {x: 0, y: 0};
p1.moveTo.apply(p2, [10, 10]);//apply实际上为p2.moveTo(10,10)
p2.x//10
apply 和 call 调用中的 this 指向
p1.moveTo.apply(p2,[10,10]) 函数在“JavaScript this 决策树”中的判定过程如下:
apply 和 call 方法功能强大,允许切换函数执行的上下文环境(context),即改变 this 绑定的对象。p1.moveTo.apply(p2,[10,10]) 实际上等价于 p2.moveTo(10,10)。因此,p2.moveTo(10,10) 可解释为:
1)判断 p2.moveTo(10,10) 是否通过 new 关键字调用?显然不是,进入“否”分支,继续判断函数是否通过点运算符(.)调用;
2)p2.moveTo(10,10) 是通过点运算符调用的,因此进入“是”分支,此时 this 指向点运算符左侧的对象 p2,故 p2.x=10;
函数执行环境解析
关于 JavaScript 函数执行环境的过程,IBM developerworks 文档库中的一段描述非常精辟,摘录如下:
“JavaScript 中的函数既可以被当作普通函数执行,也可以作为对象的方法执行,这是导致 this 含义如此丰富的主要原因。一个函数被执行时,会创建一个执行环境(ExecutionContext),函数的所有的行为均发生在此执行环境中,构建该执行环境时,JavaScript 首先会创建 arguments 变量,其中包含调用函数时传入的参数。接下来创建作用域链。然后初始化变量,首先初始化函数的形参表,值为 arguments 变量中对应的值,如果 arguments 变量中没有对应值,则该形参初始化为 undefined。如果该函数中含有内部函数,则初始化这些内部函数。如果没有,继续初始化该函数内定义的局部变量,需要注意的是此时这些变量初始化为 undefined,其赋值操作在执行环境(ExecutionContext)创建成功后,函数执行时才会执行,这点对于我们理解 JavaScript 中的变量作用域非常重要,鉴于篇幅,我们先不在这里讨论这个话题。最后为 this 变量赋值,如前所述,会根据函数调用方式的不同,赋给 this 全局对象,当前对象等。至此函数的执行环境(ExecutionContext)创建成功,函数开始逐行执行,所需变量均从之前构建好的执行环境(ExecutionContext)中读取。”
深入理解这段描述对于掌握 JavaScript 函数机制大有裨益。
以上是对 JavaScript 中 this 关键字的详细介绍。通常图片比文字更易于理解,希望本文能对大家的学习有所帮助。