备战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:

  • call
  • apply
  • bind
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 的第一个参数是 nullundefined

  • 会退回到 默认绑定,即:
  • 严格模式下是 undefined
  • 非严格模式下是全局对象

new 绑定

当函数通过 new 调用时,this 会指向新创建的实例对象。

function Person(name) {
  this.name = name;
}

const p = new Person('Tom');

此时 this 的绑定过程如下:

  1. 创建一个全新的对象
  2. 将该对象的 [[Prototype]] 指向构造函数的 prototype
  3. 将 this 绑定到这个新对象
  4. 如果函数没有返回对象,则默认返回这个新对象

箭头函数的 this(特殊规则)

在 ES6 中引入了箭头函数,箭头函数没有自己的 this。它的 this 取决于 声明时所在作用域的 this,而不是调用方式。

const obj = {
  name: 'Tom',
  say: () => {
    console.log(this.name);
  }
};

obj.say(); // undefined

原因是:

  • 箭头函数声明在全局作用域
  • 它继承的是全局 this,而不是 obj

由于箭头函数的 this 不会随着调用方式改变,所以箭头函数不能作为构造函数。

this 绑定的优先级

this 的优先级从高到低:

  1. new 绑定
  2. 显式绑定(call / apply / bind)
  3. 隐式绑定
  4. 默认绑定

在面试中如果遇到,应该如何判断呢?

  1. 有没有 new → 有:this 指向新实例
  2. 有没有 call / apply → 有:this 指向第一个参数
  3. 有没有「对象.方法」 → 有:this 指向点前面的对象
  4. 都没有 → 默认绑定(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、工程化、性能优化、场景题等

全部评论

相关推荐

12-24 20:47
武汉大学 Java
点赞 评论 收藏
分享
评论
2
4
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务