[程序设计] JavaScript | 20分钟搞懂 JavaScript 中的 `this`指向问题
·
理解 this 的指向是 JavaScript 中的一个核心难点,而普通函数和箭头函数的 this 行为差异是最容易混淆的地方。我们可以用「谁调用,指向谁」(普通函数)和「在哪定义,继承谁」(箭头函数)这两句话来概括,再结合具体例子就很好理解了。
一、普通函数:this 指向「调用它的对象」(动态绑定)
普通函数的 this 不是固定的,取决于「谁在调用它」,调用方式不同,this 指向就可能不同。就像现实中「工具的使用者决定了工具的作用对象」—— 同一把螺丝刀,A 用它拧螺丝,B 用它撬东西,作用对象(类似 this)是不同的。
例子1:函数作为「对象方法」被调用
当函数是对象的一个属性(方法)时,调用这个方法的对象就是 this 的指向。
let person = {
name: "小明",
sayHi: function() {
// 谁调用 sayHi?是 person 对象
console.log(this.name); // this 指向 person,输出 "小明"
}
};
person.sayHi(); // 调用者是 person → this 指向 person
例子2:函数在「全局作用域」被调用
如果函数没有明确的调用对象(直接在全局调用),this 会指向「全局对象」(浏览器中是 window,Node 环境中是 global)。
function sayHi() {
// 没有明确调用者,默认是全局对象
console.log(this); // 浏览器中输出 window 对象
}
sayHi(); // 等价于 window.sayHi() → this 指向 window
例子3:函数作为「构造函数」被调用(用 new)
当用 new 关键字调用函数(此时函数是构造函数),this 会指向「新创建的实例对象」。
function Person(name) {
this.name = name; // this 指向新创建的实例
}
let person1 = new Person("小红");
console.log(person1.name); // "小红" → this 指向 person1 实例
总结普通函数的 this 规律:
- 谁调用函数,
this就指向谁; - 没有明确调用者 → 指向全局对象;
- 用
new调用 → 指向新实例。
二、箭头函数:this 继承自「外层作用域」(静态绑定)
箭头函数没有自己的 this,它的 this 是「定义时就固定好的」,继承自外层作用域的 this(也就是箭头函数写在哪个作用域里,就用哪个作用域的 this)。
可以理解为:箭头函数像个「复读机」,它的 this 完全照搬外层环境的 this,不管谁调用它都不会变。
例子1:箭头函数作为「对象方法」(和普通函数对比)
let person = {
name: "小明",
// 普通函数方法
sayHi1: function() {
console.log(this.name); // 调用者是 person → 输出 "小明"
},
// 箭头函数方法
sayHi2: () => {
// 箭头函数定义在 person 对象的外层(全局作用域)
// 所以 this 继承全局的 this(window),而 window 没有 name 属性
console.log(this.name); // 输出 undefined
}
};
person.sayHi1(); // 正常输出 "小明"
person.sayHi2(); // 输出 undefined(因为 this 指向 window)
关键:箭头函数 sayHi2 定义在全局作用域(person 对象只是它的载体,不是它的外层作用域),所以 this 继承全局的 window,而不是调用它的 person 对象。
例子2:箭头函数在「嵌套函数」中(解决普通函数的 this 丢失问题)
这是箭头函数最常用的场景:当需要在嵌套函数中保留外层 this 时。
let timer = {
name: "计时器",
start: function() {
// 普通函数作为定时器回调:this 会指向 window(丢失外层 this)
setTimeout(function() {
console.log("普通函数:", this.name); // 输出 "普通函数: undefined"(this 是 window)
}, 100);
// 箭头函数作为定时器回调:this 继承外层的 this(即 timer 对象)
setTimeout(() => {
console.log("箭头函数:", this.name); // 输出 "箭头函数: 计时器"(this 是 timer)
}, 100);
}
};
timer.start();
原因:
- 普通函数的回调在定时器中被
window调用,所以this指向window; - 箭头函数的回调定义在
start方法内部(外层作用域的this是timer),所以this继承timer。
总结箭头函数的 this 规律:
- 箭头函数没有自己的
this,它的this由「定义时的外层作用域」决定; - 一旦定义,
this就固定不变,无论谁调用它都不会改变; - 外层作用域指的是箭头函数「写在哪里」,而不是「被谁调用」。
三、一句话对比记忆
| 函数类型 | this 指向规则 |
核心特点 |
|---|---|---|
| 普通函数 | 谁调用,指向谁 | 动态变化(取决于调用方式) |
| 箭头函数 | 在哪定义,继承哪 | 静态固定(定义时就确定) |
实际开发中的建议
- 当需要
this指向调用对象时(比如对象的方法),用普通函数; - 当需要保留外层
this时(比如嵌套函数、回调函数),用箭头函数; - 箭头函数不适合作为对象的方法(因为
this不会指向对象本身)。
多写几个对比案例,观察 this 的输出结果,很快就能掌握这个区别了!
更多推荐

所有评论(0)