一、核心知识点(30 分钟吃透)
1. this 指向核心原则
this 指向函数执行时的调用者,而非定义时,不同调用场景指向规则不同,核心分为 5 类:
表格
| 调用场景 | this 指向 | 典型示例 |
|---|---|---|
| 全局作用域 / 普通函数调用 | 浏览器:window;Node:global | function fn() {console.log(this)} fn() |
| 对象方法调用 | 调用该方法的对象 | obj.fn() → this 指向 obj |
| 构造函数(new)调用 | 新创建的实例对象 | new Person() → this 指向实例 |
| 显式绑定(call/apply/bind) | 绑定的指定对象 | fn.call(obj) → this 指向 obj |
| 箭头函数 | 继承外层作用域的 this(无自身 this) | () => {console.log(this)} |
2. 特殊场景补充
- 定时器 / 延时器 :
setTimeout/setInterval内普通函数 this 指向 window(默认绑定),箭头函数则继承外层 this; - DOM 事件处理函数:普通函数 this 指向触发事件的 DOM 元素,箭头函数继承外层 this;
- 严格模式:全局 / 普通函数调用时 this 为 undefined(而非 window)。
二、5 道 this 指向必练题(40 分钟拆解)
题 1:全局 / 对象方法调用
js
var name = "全局";
const obj = {
name: "对象",
fn: function() {
console.log(this.name);
}
};
obj.fn(); // 答案:对象(调用者是obj)
const fn2 = obj.fn;
fn2(); // 答案:全局(调用者是window,var声明挂载到window)
题 2:定时器 + 普通 / 箭头函数
js
const obj = {
name: "小明",
fn1: function() {
setTimeout(function() {
console.log(this.name); // 答案:undefined(定时器内普通函数指向window,window无name)
}, 0);
},
fn2: function() {
setTimeout(() => {
console.log(this.name); // 答案:小明(箭头函数继承外层fn2的this,指向obj)
}, 0);
}
};
obj.fn1();
obj.fn2();
题 3:构造函数 + 显式绑定
js
function Person(name) {
this.name = name;
this.fn = function() {
console.log(this.name);
};
}
const p1 = new Person("小红");
p1.fn(); // 答案:小红(new调用,this指向实例)
const p2 = { name: "小李" };
p1.fn.call(p2); // 答案:小李(call显式绑定p2)
题 4:箭头函数 + 多层嵌套
js
const obj = {
name: "对象",
fn: () => {
console.log(this.name); // 答案:undefined(箭头函数继承外层全局this,window无name)
function inner() {
console.log(this.name); // 答案:undefined(普通函数指向window)
}
inner();
}
};
obj.fn();
题 5:严格模式 + 普通函数
js
"use strict";
function fn() {
console.log(this);
}
fn(); // 答案:undefined(严格模式全局调用this为undefined)
const obj = { fn };
obj.fn(); // 答案:obj(对象方法调用仍指向obj)
三、核心面试题 + 标准答案(20 分钟背会)
面试题:JavaScript 中 this 指向的规则有哪些?
标准答案(高级工程师视角,精简且有深度)
1. 核心绑定规则(优先级:new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定)
- 默认绑定:全局作用域 / 普通函数直接调用,非严格模式 this 指向 window(浏览器)/global(Node),严格模式为 undefined;
- 隐式绑定:函数作为对象方法调用时,this 指向调用该方法的对象(若方法被赋值给其他变量,隐式绑定失效,回归默认绑定);
- 显式绑定 :通过
call/apply/bind手动指定 this 指向,bind 为永久绑定(返回新函数,原函数 this 不变); - new 绑定:构造函数通过 new 调用时,this 指向新创建的实例对象(new 会创建空对象、绑定 this、执行构造函数、返回实例);
- 箭头函数绑定:箭头函数无自身 this,继承外层最近作用域的 this(无法通过 call/apply/bind 修改,也不适用 new 绑定)。
2. 特殊场景补充(体现工程化思维)
- 定时器 / 延时器内普通函数 this 指向 window,箭头函数可解决 "丢失 this" 问题;
- DOM 事件回调中,普通函数 this 指向触发事件的 DOM 元素,箭头函数继承外层 this(常用于 React 组件事件);
- 实际开发中,优先用箭头函数简化 this 绑定(如 Vue 组件 methods 内嵌套函数、React 事件处理),避免手动 bind。
3. 实战示例(面试加分)
js
// 业务场景:解决定时器内this丢失问题
class Component {
constructor() {
this.name = "组件";
// 传统方式:bind绑定
this.fn1 = this.fn1.bind(this);
}
// 推荐方式:箭头函数(class字段)
fn2 = () => {
setTimeout(() => {
console.log(this.name); // 组件(继承外层fn2的this)
}, 0);
};
fn1() {
setTimeout(function() {
console.log(this.name); // 组件(bind绑定后指向实例)
}, 0);
}
}
四、错题整理模板(10 分钟完成)
表格
| 错题类型 | 错误代码 / 场景 | 错误原因 | 正确思路 / 知识点 |
|---|---|---|---|
| 箭头函数 this 误解 | 认为箭头函数 this 可通过 call 修改 | 忽略箭头函数无自身 this 的特性 | 箭头函数 this 继承外层,无法手动修改 |
| 定时器 this 丢失 | 定时器内普通函数期望指向对象 | 定时器默认绑定 window | 改用箭头函数或提前保存 this(const that = this) |
| 显式绑定优先级错误 | 认为 bind 绑定可被 call 覆盖 | 忽略 bind 是永久绑定 | bind 返回的新函数 this 不可被 call/apply 修改 |
总结
- 核心考点:this 指向的核心是 "执行时绑定",优先级顺序和箭头函数特性是面试高频考点;
- 实战重点:解决业务中 "this 丢失" 问题(箭头函数 /bind/ 保存 that),是前端开发必备技能;
- 易错点:混淆箭头函数与普通函数的 this 规则、忽略严格模式对 this 的影响。