JavaScript this关键字详解:规则、场景与避坑指南
本文深入解析JavaScript中this关键字的动态指向规则。文章从全局环境、对象方法及构造函数等核心场景出发,详细说明其默认绑定与隐式绑定的区别。针对多层嵌套、数组处理及回调函数中常见的this丢失问题,提供了使用that变量缓存、apply/bind或strict mode的有效解决方案。
核心定义与基本规则
在JavaScript中,this关键字总是返回一个对象。具体来说,它指的是属性或方法“当前”所在的执行上下文对象。理解这一概念的关键在于:this的指向是动态的,取决于函数是如何被调用的,而不是函数在哪里被定义。
第1步:理解默认环境下的this
- 目的:明确非特定调用方式下this的基础指向。
- 操作观察:
var name = 'keith';
function person() {
var name = 'rascal'; // 局部变量
return this.name; // 这里的this指向全局window
}
console.log(person()); // 输出: 'keith'
在全局作用域下定义的函数(非严格模式),若直接调用,this指向顶层对象(浏览器中为window)。如果函数内部未使用var声明变量,则会修改全局同名变量,从而产生副作用。
第2步:掌握对象的隐式绑定
- 目的:掌握当方法依附于对象时,this如何随对象变化。
- 原理:当对象的方法被赋值给另一个对象或变量时,this会指向新的调用者。
var Keith = { firstName: 'Chou', describe: function() { return this.firstName; } };
var Rascal = { firstName: 'King' };
Rascal.describe = Keith.describe; // 引用传递
console.log(Rascal.describe()); // 输出: 'King'
此例说明,只要函数作为某个对象的属性被调用,this就指向该对象。若将Keith.describe赋值给独立变量f并调用,由于失去了对象载体,this将回落至全局window。
主要应用场景解析
第1步:全局环境中的应用
- 入口:任何未被包裹在对象内的函数调用。
- 状态:在非严格模式下,
this === window。在严格模式('use strict';)下,全局函数中的this值为undefined。
第2步:构造函数中的this
- 目的:在实例化过程中为新对象初始化属性。
- 关键参数:必须使用
new关键字调用。
function Keith() {
this.sex = 'boy';
}
var person = new Keith();
console.log(person.sex); // 输出: 'boy'
使用new时,JS引擎会创建一个新对象,并将函数内部的this绑定到这个新对象上。最后隐式返回该对象(除非构造函数显式return了复杂对象)。
第3步:对象方法中的this
- 注意:多层嵌套对象中,若提取内部方法至全局变量,this将失效。
var a = { b: { p: 'keith', c: function() { return this.p; } } };
var person = a.b.c;
console.log(person()); // 输出: undefined (此时this指向window)
解决之道是直接通过对象链访问(a.b.c()),或将所在父对象(a.b)赋给变量。
常见陷阱与解决方案
第1步:避免多层嵌套/闭包导致的this丢失
- 现象:在外部对象的方法内部定义内部函数(如IIFE或普通函数),内部函数的this往往指向window而非外层对象。
var o = {
f1: function() {
console.log(this); // Object
(function() {
console.log(this); // Window
})();
}
};
解决方案A:使用that/catch-this变量
var o = {
f1: function() {
var that = this; // 捕获外层this
(function() {
console.log(that); // Object
})();
}
};
解决方案B:使用严格模式
在开启严格模式的函数中,若this意外指向window,通常会抛出错误,这有助于提前发现逻辑漏洞。但在ES6箭头函数出现前,严格模式并不能自动修复this指向错误的业务需求,更多用于调试保护。
第2步:处理数组方法中的this
- 现象:
forEach,map等回调函数中的this默认指向window或undefined。
var keith = {
a: 'Hello',
b: ['b1', 'b2'],
c: function() {
this.b.forEach(function(item) {
console.log(this.a + ' ' + item); // 报错或undefined,因为this指向window
})
}
};
解决方案A:传入this作为第二个参数
大多数数组迭代方法接受callback和thisArg两个参数。
this.b.forEach(function(item) {
console.log(this.a + ' ' + item);
}, this); // 强制this指向keith
解决方案B:使用var that = this
同嵌套函数方案,利用闭包特性保留外层this引用。
第3步:事件回调中的this变更
- 现象:当对象方法作为DOM事件处理器绑定时,this指向触发事件的DOM元素,而非原对象。
// jQuery示例
$('button').on('click', o.f);
// 此时o.f内部的this指向button DOM对象,而非o对象
解决方案
使用Function.prototype.bind或箭头函数来固定this指向。
// ES5
$('button').on('click', o.f.bind(o));
// ES6 Arrow Function (推荐)
o.f = () => {
console.log(this === o); // true
};
总结
JavaScript中的this始终指向调用当前函数的对象。在全局作用域或非严格模式下的普通函数调用中,它指向window;在对象方法中,它指向该方法所属的对象;在构造函数中,它指向新创建的实例。面对回调、嵌套函数等导致上下文分离的场景,开发者应通过bind、箭头函数或临时变量(如that)来锁定预期的this值。以上就是JavaScript中this关键字的详细解析,更多关于前端基础知识的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









