在 JavaScript 中,this
是一个非常特殊的关键字,它不像普通变量那样固定不变,而是 "见风使舵"------谁调用函数,this
就指向谁 。理解 this
是掌握 JavaScript 的关键一步,因为它直接影响代码的执行结果。
一、什么是 this?
this
可以理解为函数的 "上下文",也就是函数在执行时所处的环境。它的作用是隐式传递对象引用,让代码更简洁。比如:
javascript
const user = {
name: "张三",
sayHi() {
console.log(`你好,我是${this.name}`); // 这里的this就代表user对象
}
};
user.sayHi(); // 输出:你好,我是张三
如果没有 this
,我们可能需要写成 console.log(user.name)
,当对象名称变化时,所有引用都要修改,而 this
帮我们避免了这种麻烦。
二、不同场景下的 this 指向
this
的指向不是在定义函数时决定的,而是在函数被调用时 决定的。不同的调用方式,this
会指向不同的对象。
1. 全局作用域中的 this
在全局作用域(不在任何函数内),this
直接指向全局对象:
-
浏览器环境中,全局对象是
window
-
Node.js 环境中,全局对象是
global
javascript
console.log(this === window); // 浏览器中输出 true
console.log(this); // 直接打印全局对象(包含大量内置属性和方法)
2. 函数作用域中的 this
函数中的 this
指向调用该函数的对象,具体分四种绑定规则:
规则一:默认绑定(独立函数调用)
当函数独立调用(没有被任何对象 "点" 调用)时,this
指向全局对象。
javascript
function a() {
console.log(this);
}
a(); // 独立调用,this指向window(浏览器环境)

注意 :在严格模式("use strict"
)下,默认绑定的 this
会变成 undefined
,而不是全局对象。
规则二:隐式绑定(对象调用函数)
当函数被某个对象调用(即通过 对象.函数()
的形式)时,this
指向这个调用函数的对象。
javascript
const obj = {
name: "李四",
sayName() {
console.log(this.name); // this指向obj
}
};
obj.sayName(); // 输出:李四(因为是obj调用了sayName)
javascript
var a = 1
function foo() {
console.log(this.a) // 2
}
var obj = {
a:2,
foo:foo
}
obj.foo() //函数foo被obj调用,this指向obj

如果函数被多层对象嵌套调用,this
指向最近的那个调用对象(离函数最近的 "点" 前面的对象):
javascript
const obj1 = {
a: 1,
obj2: {
a: 2,
showA() {
console.log(this.a); // this指向obj2(最近的调用对象)
}
}
};
obj1.obj2.showA(); // 输出:2
css
var a = 1
function foo() {
console.log(this.a); //obj.a
}
var obj = {
a:2,
foo:foo
}
var obj2 = {
a:3,
obj:obj
}
obj2.obj.foo()

规则三:显式绑定(强制修改 this 指向)
我们可以通过 call
、apply
、bind
这三个方法,主动指定函数的 this
指向,不管函数原本该指向谁。
这三个方法的作用类似,但用法有区别:
方法 | 语法 | 特点 |
---|---|---|
call |
函数.call(指向的对象, 参数1, 参数2...) |
直接调用函数,参数逐个传入 |
apply |
函数.apply(指向的对象, [参数1, 参数2...]) |
直接调用函数,参数以数组形式传入 |
bind |
const 新函数 = 函数.bind(指向的对象, 参数1, 参数2...) |
不立即调用,返回一个绑定好 this 的新函数 |
javascript
function introduce(age, hobby) {
console.log(`我是${this.name},年龄${age},爱好${hobby}`);
}
const person = { name: "王五" };
// call用法
introduce.call(person, 20, "打篮球"); // 输出:我是王五,年龄20,爱好打篮球
// apply用法(参数用数组)
introduce.apply(person, [20, "打篮球"]); // 输出同上
// bind用法(返回新函数,需要手动调用)
const boundFunc = introduce.bind(person, 20, "打篮球");
boundFunc(); // 输出同上
规则四:new 绑定(构造函数调用)
当用 new
关键字调用函数(此时函数作为构造函数)时,this
指向新创建的对象。
javascript
function Person(name) {
this.name = name; // this指向new创建的新对象
}
const p1 = new Person("赵六");
console.log(p1.name); // 输出:赵六(this将name赋值给了p1)
javascript
const obj = {
name: '111',
show:function() {
console.log(this.name);
}
};
obj.show(); // 111

dart
const obj = {
name: '111',
show: () => {
console.log(this.name); // 不是111,而是外层this
}
};
obj.show();

new
关键字的执行过程(结合 this
理解):
- 创建一个空对象(
{}
) - 让构造函数的
this
指向这个空对象 - 执行构造函数代码(给空对象添加属性,空对象的隐式原型 __ proto__ ===构造函数的显示原型prototype)
- 返回这个新对象
规则优先级
如果同时满足多个规则,优先级顺序为:
new 绑定 > 显式绑定(call/apply/bind) > 隐式绑定(对象调用) > 默认绑定(独立调用)
3. 箭头函数中的 this(特殊情况)
箭头函数是个例外 ------它没有自己的 this
,它的 this
继承自外层作用域的 this
,且一旦确定就不会改变。
javascript
const obj = {
name: "箭头函数测试",
// 普通函数:this指向obj
normalFunc() {
console.log(this.name);
},
// 箭头函数:this继承外层作用域(这里外层是全局)
arrowFunc: () => {
console.log(this.name);
}
};
obj.normalFunc(); // 输出:箭头函数测试(this指向obj)
obj.arrowFunc(); // 输出:undefined(this指向window,而window.name可能未定义)
常见坑点 :在对象方法中使用箭头函数,可能导致 this
指向不符合预期(如上例)。箭头函数更适合在嵌套函数中使用,解决 this
丢失问题:
javascript
const timerObj = {
name: "计时器",
start() {
// 普通函数作为定时器回调,this会指向window
setTimeout(function() {
console.log(this.name); // 输出:undefined
}, 1000);
// 箭头函数作为回调,this继承自start的this(即timerObj)
setTimeout(() => {
console.log(this.name); // 输出:计时器
}, 1000);
}
};
timerObj.start();
三、特殊场景中的 this
1. DOM 事件处理函数
在 DOM 事件回调中,this
指向触发事件的元素:
xml
<button id="btn">点击我</button>
<script>
const btn = document.getElementById("btn");
btn.onclick = function() {
console.log(this); // 指向按钮元素(<button>)
this.style.color = "red"; // 可以直接操作当前元素
};
</script>
2. 定时器 / 延时器回调
setTimeout
的回调函数中,this
默认指向全局对象(window):
javascript
const obj = { name: "定时器" };
setTimeout(function() {
console.log(this); // 指向window,而非obj
console.log(this.name); // 输出:undefined
}, 1000);
解决办法:用箭头函数继承外层 this
,或用 bind
绑定:
javascript
// 方法1:箭头函数
setTimeout(() => {
console.log(this); // 继承外层this(如果外层this是obj的话)
}, 1000);
// 方法2:bind绑定
setTimeout(function() {
console.log(this.name);
}.bind(obj), 1000); // 输出:定时器
3. 类中的 this
-
类的普通方法中,
this
指向实例对象 -
类的静态方法(用
static
修饰)中,this
指向类本身
javascript
class Student {
constructor(name) {
this.name = name; // 普通方法(构造函数),this指向实例
}
sayName() {
console.log(this.name); // this指向实例
}
static showClass() {
console.log(this); // 静态方法,this指向Student类本身
}
}
const stu = new Student("小明");
stu.sayName(); // 输出:小明
Student.showClass(); // 输出:class Student { ... }
四、避免 this 丢失的实用技巧
this
丢失是开发中常见问题(比如将对象方法赋值给变量后调用),解决办法:
-
用
bind
提前绑定this
:goconst obj = { name: "绑定测试", getName() { return this.name; } }; const func = obj.getName.bind(obj); // 绑定this为obj console.log(func()); // 输出:绑定测试
-
用箭头函数继承外层
this
:javascriptconst obj = { name: "箭头绑定", getFunc() { return () => { return this.name; }; // 箭头函数继承getFunc的this(即obj) } }; const func = obj.getFunc(); console.log(func()); // 输出:箭头绑定
总结
理解 this
的核心是记住:谁调用函数,this
就指向谁。具体场景可归纳为:
- 普通函数独立调用:
this
指向全局对象(严格模式为undefined
) - 对象调用函数:
this
指向该对象 call/apply/bind
调用:this
指向指定对象new
调用构造函数:this
指向新创建的实例- 箭头函数:
this
继承自外层作用域,永不改变