

在JavaScript的学习与开发中,`this`关键字常被视为令人困惑的概念之一。然而,其行为实际上遵循一套明确且一致的规则:`this`的指向在函数调用时确定,取决于函数的调用方式,而非定义位置。理解这一核心原则,便能准确预测各种场景下`this`的值,并规避常见的陷阱。
一、澄清常见误解
误解一:`this`指向函数自身。
事实:`this`与函数对象本身无直接关联,除非在特定调用模式下(如构造函数)才指向新创建的实例。
误解二:`this`指向函数定义时的作用域。
事实:`this`的绑定基于调用栈与调用上下文,与词法作用域无关。唯一例外是箭头函数,它不绑定自己的`this`,而是继承外层词法作用域的`this`。
二、四种核心调用场景与`this`指向规则
2.1全局调用:独立函数调用
当函数以无任何对象前缀的方式直接调用时,`this`指向全局对象。在浏览器环境中为`window`,在Node.js中为`global`。
```javascript
functiongreet(){
console.log(this===window);//true(浏览器环境)
}
greet();//独立调用,this指向全局对象
```
2.2对象方法调用:点符号或方括号调用
当函数作为对象的属性,并通过该对象调用时,`this`指向该对象(即函数的直接调用者)。
```javascript
constuser={
name:'Alice',
sayName:function(){
console.log(this.name);//'Alice'
}
};
user.sayName();//调用者为user,this指向user
```
2.3构造函数调用:`new`关键字
使用`new`调用函数时,会执行以下步骤:
1.创建一个空对象,将其原型链接至构造函数的`prototype`。
2.将该对象绑定为构造函数的`this`。
3.执行构造函数体(通常为对象添加属性)。
4.返回该对象(若构造函数无显式返回对象)。
```javascript
functionPerson(name){
this.name=name;//this指向新创建的实例
}
constp=newPerson('Bob');
console.log(p.name);//'Bob'
```
2.4箭头函数:词法`this`绑定
箭头函数不定义自己的`this`,其`this`值继承自外层(非箭头)函数的作用域。这一特性使箭头函数特别适合用于需要保留外层上下文的回调场景。
```javascript
constobj={
count:0,
start:function(){
//普通函数,this指向obj
setInterval(()=>{
//箭头函数,继承外层start的this(即obj)
this.count++;
console.log(this.count);//1,2,3...
},1000);
}
};
obj.start();
```
三、典型陷阱与解决方案
3.1定时器回调中的`this`丢失
问题:将普通函数作为定时器回调时,该函数由全局对象调用,其内部`this`指向全局对象,而非期望的外层对象。
```javascript
constobj={
count:0,
start:function(){
setInterval(function(){
this.count++;//this指向window,count为undefined
},1000);
}
};
obj.start();//NaN
```
解决方案:
箭头函数(推荐):利用其词法`this`绑定特性。
```javascript
start:function(){
setInterval(()=>{
this.count++;
},1000);
}
```
`bind`方法:显式绑定回调函数的`this`。
```javascript
start:function(){
setInterval(function(){
this.count++;
}.bind(this),1000);
}
```
保存`this`引用(ES6前经典做法):
```javascript
start:function(){
constthat=this;
setInterval(function(){
that.count++;
},1000);
}
```
3.2箭头函数作为对象方法
问题:将箭头函数定义为对象的方法时,其`this`继承自外层作用域(通常是全局对象),而非对象本身。
```javascript
constobj={
name:'Charlie',
sayName:()=>{
console.log(this.name);//undefined(this指向window)
}
};
obj.sayName();
```
结论:对象方法应使用普通函数定义,以正确接收调用者作为`this`。
3.3同一函数不同调用导致`this`变化
`this`的指向完全由调用方式决定,同一函数可作为不同对象的方法,从而拥有不同的`this`。
```javascript
functionidentify(){
console.log(this.name);
}
constobj1={name:'David',identify};
constobj2={name:'Eve',identify};
identify();//undefined(全局调用)
obj1.identify();//'David'
obj2.identify();//'Eve'
```
四、判断`this`的三步法
遇到`this`相关问题,可按以下步骤推理:
1.定位调用位置:找出函数被调用的代码行,观察调用时的语法形式。
2.识别调用模式:判断属于全局调用、对象方法调用、构造函数调用,还是箭头函数。
3.应用对应规则:
全局调用→`this`指向全局对象。
对象方法调用→`this`指向点符号左侧的对象。
`new`调用→`this`指向新创建的实例。
箭头函数→`this`继承自外层最近的非箭头函数作用域。
五、总结
| 调用方式 | `this`指向 | 示例 |
| 独立函数调用 | 全局对象(浏览器中为`window`) | `fn()` |
| 对象方法调用 | 调用该方法的对象 | `obj.fn()` |
| 构造函数调用 | 新创建的实例 | `newFn()` |
| 箭头函数 | 继承外层非箭头函数的`this` | `()=>{}` |
| 显式绑定(`call`/`apply`/`bind`) | 指定的对象 | `fn.call(obj)` |
核心原则:`this`的指向在函数执行时确定,由调用者与调用方式共同决定。掌握这一原则,即可从容应对JavaScript中所有与`this`相关的场景。

一家致力于优质服务的软件公司
8年互联网行业经验1000+合作客户2000+上线项目60+服务地区

关注微信公众号
