图解JavaScript中的this关键字:决策树与实战解析
JavaScript 的 this 关键字因其基于运行期的动态绑定特性,常被开发者视为入门难点。与其他编译期绑定的语言不同,this 的具体指向完全取决于函数的调用方式。掌握其核心逻辑,是理解 JavaScript 执行环境的关键。
结果或目标
在处理 JavaScript 代码时,准确判断 this 所引用的对象(全局对象、当前实例对象或指定上下文)至关重要。错误的绑定会导致数据污染、空引用错误或预期的行为偏差。通过理解决策树逻辑,可以在任何调用场景下快速确定 this 的归属。
准备条件
- 具备基础的 JavaScript 函数与对象概念。
- 理解非严格模式(Non-strict Mode)下的默认行为(如全局变量挂载)。
- 熟悉
function定义及基本的点语法(Dot Notation)调用。
真实操作顺序
第1步:理解核心差异与决策树模型
在 Java、C# 等面向对象语言中,this 通常指代当前实例,且绑定发生在编译期。而 JavaScript 作为脚本语言,this 的绑定发生在运行期。这意味着 this 可以是全局对象、当前调用对象,甚至是被强制切换到的任意对象。
为了直观判断,可参考以下“JavaScript this 决策树”逻辑(基于非严格模式):

该决策树的核心路径为:
1. 是否使用 new 关键字调用?
2. (若非 new)是否使用 .(点号)或 [ ] 进行调用?
3. (若以上皆非)是否存在 call 或 apply 的显式指定?
第2步:对象方法调用(点语法)
当函数作为对象的属性被访问并调用时,this 指向调用该方法的对象实例。
示例代码分析:
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
// 这里的 this 指向 point 对象
this.x = this.x + x;
this.y = this.y + y;
}
};
// 调用动作:point.moveTo(1,1)
point.moveTo(1,1);
// 决策树路径:非 new -> 使用 dot(.) 调用 -> this 指向 . 前的对象 (point)
在此场景中,point.moveTo 是一个函数引用,但当它后面紧跟括号时,JS 引擎将其识别为对 point 对象属性的执行。因此,内部的 this 自动绑定到 point 对象上,实现了对 x 和 y 属性的修改。
图解 moveTo 函数的 this 指向逻辑如下:
第3步:直接函数调用(Global/Fallback)
当函数独立调用(即不作为任何对象的方法,也不使用 new)时,在非严格模式下,this 默认指向全局对象(在浏览器中为 window)。
示例代码分析:
function func(x) {
this.x = x;
}
// 调用动作:func(5),非 new,非 dot 调用
func(5);
// 此时 this === window
// 等同于 window.x = 5
x; // 输出 5,因为全局变量 x 被创建
如果在调用链中既没有 new 也没有 .,则落入最后的默认分支:this 指向全局环境。这解释了为什么上述代码执行后,外部可以通过 x 直接访问到值 5,因为它实际上挂载到了全局作用域。
图解 func 函数的 this 指向逻辑如下:

第4步:嵌套函数中的陷阱
在实际开发中,最易出错的是对象方法内部定义的回调或子函数。这些内部函数如果未被特殊处理,其调用方式往往退化为“直接函数调用”。
复杂示例分析:
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
// 内部函数 moveX 独立存在
var moveX = function(x) {
this.x = x; // 这里的 this 指向谁?
};
moveX(x);
}
};
point.moveTo(1,1);
console.log(point.x); // 0 (未改变)
console.log(x); // 1 (全局变量被赋值)
判定过程:
1. moveX(1) 调用时,前面没有 new。
2. 调用形式不是 obj.moveX(),而是直接函数名 moveX()。
3. 根据决策树“否 → 否”分支,this 指向全局对象 window。
结果: point.x 保持为 0,而全局变量 x 被赋值为 1。这在现代 JS 开发中通常是 Bug 来源,常通过 let self = this 或箭头函数解决。
第5步:构造函数调用(New)
使用 new 关键字调用函数时,会创建一个新对象,并将函数内的 this 绑定到这个新对象上。
示例代码分析:
function Point(x, y) {
this.x = x;
this.y = y;
}
// 情况 A:正确使用 new
var np = new Point(1, 1);
np.x; // 1。决策树:Yes(new) -> this 指向新实例 np
// 情况 B:忘记 new
var p = Point(2, 2);
p.x; // error/p is undefined
window.x; // 2。决策树:No(new) -> No(dot) -> this 指向 window
必须注意 new 的存在与否。缺少 new 不仅会导致返回值错误,还会意外污染全局命名空间(如上面的 window.x)。
第6步:显式绑定(Call / Apply)
call 和 apply 允许强行改变函数执行时的上下文环境(Context),即手动指定 this 的值。
示例代码分析:
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 的 this 绑定到 p2
p1.moveTo.apply(p2, [10, 10]);
// 等同于 p2.moveTo(10, 10)
p2.x; // 10
p2.y; // 10
判定过程:
虽然底层实现是 apply,但就 this 的最终归宿而言,我们可以理解为函数已经在新的上下文(p2)中成为了一个对象方法。或者从另一个角度理解:显式绑定优先级最高,this 直接被强制设定为第一个参数指定的对象(即 p2)。在决策树语境下,这相当于人为地将调用方式伪装成了对象方法调用或直接注入上下文。
完成判断
判断 this 的核心依据在于函数的直接调用者是谁。
- 有 new,绑定到新实例。
- 无 new 但有 .(或类似 obj['func']()),绑定到 . 前的对象。
- 无 new 且无 .,非严格模式下绑定到全局对象 window。
- 使用了 bind/call/apply,绑定到传入的第一个参数对象。
简要总结
JavaScript 函数的执行环境(ExecutionContext)在创建时初始化变量和作用域链,最后一步才为 this 赋值。这一动态过程赋予了 JS 极大的灵活性,但也增加了理解的复杂度。无论是对象方法的隐式绑定,还是构造函数的实例绑定,亦或是 call/apply 的显式劫持,本质上都是对执行上下文中 this 值的定位。理清这四类调用方式及其对应的 this 指向,即可应对绝大多数关于 this 的场景问题。
以上就是图解JavaScript中this关键字的详细解析,更多关于JavaScript基础语法的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













