备战26春招,彻底搞懂前端八股之 this 指向:知识点讲解+面试示例回答
知识点讲解
在 JavaScript 中,函数内部的this 指向是一个非常基础、非常核心,但极其容易出错的知识点。
很多同学在面试中知道结论,却说不清「为什么是这样」「在复杂调用场景下如何判断 this」。
本文将从 this 的本质含义 出发,系统讲清 this 的所有绑定规则、常见陷阱,以及面试中一口气说清楚的标准回答。
this 的本质含义
在 JavaScript 中,this 表示普通函数当前的调用者。
换句话说:
this 的作用,是让函数在执行时,能够知道「是谁在调用我」,而不用每次都显式传入这个对象。
非常重要的一点:
- this 只和函数的调用方式有关
- 和函数的声明位置 没有任何关系
这里的「普通函数」,指的是 非箭头函数。
this 的几种绑定规则
在 JS 中,this 的绑定一共可以分为以下几种情况:
- 默认绑定
- 隐式绑定
- 显式绑定
- new 绑定
- 箭头函数绑定(特殊规则)
下面我们逐一讲解。
默认绑定
当一个函数被 直接调用,而不是作为对象的方法调用时,就会触发默认绑定。
function foo() {
console.log(this);
}
foo();
此时 this 的指向取决于运行环境和是否是严格模式:
- 非严格模式浏览器环境:windowNode 环境:global
- 严格模式this 指向 undefined
'use strict';
function foo() {
console.log(this);
}
foo(); // undefined
隐式绑定
当我们使用 对象.方法() 的形式调用函数时,会触发隐式绑定。
const obj = {
name: 'Tom',
sayName() {
console.log(this.name);
}
};
obj.sayName(); // Tom
一句话总结:
谁点了函数,this 就指向谁。
有两种特殊情况:
情况一:多层对象调用
const a = {
b: {
say() {
console.log(this);
}
}
};
a.b.say(); // this 指向 b
注意:this 指向的是 最后一次点之前的对象,而不是最外层对象。
情况二:隐式丢失(非常常考)
const obj = {
name: 'Tom',
say() {
console.log(this.name);
}
};
const fn = obj.say;
fn(); // undefined(或 window.name)
原因是:
fn只是一个函数引用- 调用时已经和
obj没有关系 - 相当于普通函数调用 → 默认绑定
另一种隐式丢失场景:作为参数传递
function callFn(fn) {
fn();
}
callFn(obj.say); // this 丢失
显式绑定(call / apply / bind)
根据原型链文章我们知道,所有函数都可以访问 Function.prototype,而其中有三个方法可以显式改变 this:
callapplybind
function foo() {
console.log(this);
}
foo.call(obj); // this → obj
foo.apply(obj); // this → obj
call / apply 的区别
call(thisArg, arg1, arg2, ...)apply(thisArg, [arg1, arg2, ...])
bind 的特点
const boundFn = foo.bind(obj); boundFn(); // this 永远是 obj
bind 不会立即执行函数,而是返回一个 this 已经绑定的新函数。
注意一个细节(面试加分)
如果 call / apply / bind 的第一个参数是 null 或 undefined:
- 会退回到 默认绑定,即:
- 严格模式下是
undefined - 非严格模式下是全局对象
new 绑定
当函数通过 new 调用时,this 会指向新创建的实例对象。
function Person(name) {
this.name = name;
}
const p = new Person('Tom');
此时 this 的绑定过程如下:
- 创建一个全新的对象
- 将该对象的
[[Prototype]]指向构造函数的prototype - 将 this 绑定到这个新对象
- 如果函数没有返回对象,则默认返回这个新对象
箭头函数的 this(特殊规则)
在 ES6 中引入了箭头函数,箭头函数没有自己的 this。它的 this 取决于 声明时所在作用域的 this,而不是调用方式。
const obj = {
name: 'Tom',
say: () => {
console.log(this.name);
}
};
obj.say(); // undefined
原因是:
- 箭头函数声明在全局作用域
- 它继承的是全局 this,而不是 obj
由于箭头函数的 this 不会随着调用方式改变,所以箭头函数不能作为构造函数。
this 绑定的优先级
this 的优先级从高到低:
- new 绑定
- 显式绑定(call / apply / bind)
- 隐式绑定
- 默认绑定
在面试中如果遇到,应该如何判断呢?
- 有没有
new→ 有:this 指向新实例 - 有没有
call / apply→ 有:this 指向第一个参数 - 有没有「对象.方法」 → 有:this 指向点前面的对象
- 都没有 → 默认绑定(window / global / undefined)
面试回答示例
面试官问:你如何理解 JavaScript 中的 this?
示范回答:
this 的含义是当前函数的调用者,取决于调用方式而不是声明的位置。this 绑定方式分为默认绑定、隐式绑定、显式绑定、new 绑定、箭头函数绑定这几种情况。首先是默认绑定,如果直接执行函数,那么 this 指向会是全局对象或 undefined,如果在严格模式下,就是 undefined,否则就是浏览器全局对象 window 或者 Node 全局对象 global。其次是隐式绑定,如果我们通过「对象点方法」,比如 obj.func() 的方式调用函数,则 this 会指向这个对象,但是要注意,假设我们 func1 = obj.func,那么在后续调用 func1 的时候,this 不会指向 obj,而是取决于 func1 本身的调用方式,这叫做 this 的隐式丢失。然后显式绑定,就是通过 call、apply、bind 来改变 this 指向,此时 this 会指向 call、apply、bind 的第一个参数,如果第一个参数是 null 或 undefined,会应用默认绑定。再然后是 new 绑定,如果我们使用 new func() 的方式,把 func 作为构造函数来创建实例对象,那么 this 就会指向新创建的实例对象。最后是箭头函数。箭头函数比较特殊,它没有自己的 this,会继承声明时父函数的 this 指向。这也是箭头函数不能作为构造函数的原因之一。
内容来源于:前端新一水公众号
#前端实习准备##前端实习##前端实习面试##前端八股#前端新一水八股系列,每日讲解一道面试高频八股题,涵盖CSS、JS、Vue、React、工程化、性能优化、场景题等
查看1道真题和解析