面试阿里,这道前端题让我犯难

    xiaoxiao2022-07-02  81

    本文来源 | 前端开发核心知识进阶

    作者 | 侯策

    编辑 | 林瑟

    JavaScript 中的 this,因其灵活的指向、复杂的使用场景一直是面试中的热点,不论是初级还是中高级开发者,这都是一道必考题。这个概念虽然基础,但是非常重要,是否能深刻理解 this,是前端 JavaScript 中进阶的重要一环。

    this 指向多变,很多隐蔽的 bug 都缘于它。与此同时,this 强大灵活,如果能熟练驾驭,就会写出更简洁、优雅的代码。

    本文this 相关知识点如下:

    01

    this 到底指向谁

    曾经在面试阿里某重点部门时,面试官从多个角度考察过我对 this 的理解:全局环境下的this、箭头函数的 this、构造函数的 thisthis 的显隐性和优先级,等等。尽管我能一一作答,可是最后的问题:请用一句话总结this的指向,注意只用一句话,我却犯难了。有一种广泛流传的说法是:

    谁调用它,this 就指向谁。

    也就是说,this 的指向是在调用时确定的。这么说没有太大的问题,可是并不全面。面试官要求我用更加规范的语言进行总结,那么他到底在等什么样的回答呢?

    我们还要回到 JavaScript 中一个最基本的概念分析——执行上下文,事实上,调用函数会创建新的属于函数自身的执行上下文。执行上下文的调用创建阶段会决定 this 的指向。到此,我们可以得出的一个结论:

    this 的指向,是在调用函数时根据执行上下文所动态确定的。

    具体环节和规则,可以先“死记硬背”以下几条规律:

    在函数体中,简单调用该函数时(非显式/隐式绑定下),严格模式下this 绑定到 undefined,否则绑定到全局对象 windowglobal

    一般构造函数 new 调用,绑定到新创建的对象上;

    一般由 call/apply/bind 方法显式调用,绑定到指定参数的对象上;

    一般由上下文对象调用,绑定在该对象上;

    箭头函数中,根据外层上下文绑定的 this 决定 this 指向。

    当然,真实环境多样,我们来看几个实例分析一下。

    02

    实战例题分析

    例题1. 全局环境下的 this

    这种情况相对简单直接,函数在浏览器全局环境中被简单调用,非严格模式下this 指向 window use strict 指明严格模式的情况下就是undefined我们来看例题,请描述打印结果:

    这样的题目比较基础,但是需要候选人格外注意其变种,请再看一道题目:

    这里 this 仍然指向的是 window虽然 fn 函数在 foo 对象中作为方法被引用,但是在赋值给 fn1 之后fn1 的执行仍然是在 window 的全局环境中。因此输出 window 和 undefined它们相当于:

    这样的题目比较基础,但是需要候选人格外注意其变种,请再看一道题目:

    这里 this 仍然指向的是 window。虽然 fn 函数在 foo 对象中作为方法被引用,但是在赋值给 fn1 之后,fn1 的执行仍然是在 window 的全局环境中。因此输出 window  undefined它们相当于:

    还是上面这道题目,如果调用改变为:

    将会输出:

    因为这个时候 this 指向的是最后调用它的对象,在 foo.fn() 语句中this 指向 foo 对象。请记住:

    在执行函数时,如果函数中的 this 是被上一级的对象所调用,那么this 指向的就是上一级的对象;否则指向全局环境。

    以上只是一道实战例题分析,不知是否已经把你绕晕了。事实上,this 的指向涉及的规范繁多,优先级也较为混乱。刻意刁难并不是很好的面试做法,一些细节候选人如果没有记住也不是太大的问题。作为面试官,我往往会另辟蹊径,出一些开放性题目。

    03

    实现一个 bind 函数

    作为面试者,我也曾经在头条的面试流程中被问到模拟 bind这道题并不新鲜,有的朋友也会有自己的解答思路,而且社区上关于原生 bind 的研究也很多。但是,我这里想强调的是。在回答时,我往往先实现一个初级版本,然后根据 ES5-shim 源码进一步说明。

    这样的实现已经非常不错了。但是,就如同之前 this 优先级分析所示:bind 返回的函数如果作为构造函数,搭配 new 关键字出现的话,我们的绑定 this 就需要“被忽略”。

    为了实现这样的规则,开发者就应该需要考虑如何区分这两种调用方式。具体来讲 bound 函数中就要进行 this instanceof 的判断。

    另外一个细节是,函数具有 length 属性,表示形参的个数。上述实现方式形参的个数显然会失真。我们的实现就需要对 length 属性进行还原。可是难点在于:函数的 length 属性值是不可重写的。

    这样的内容一般属于“超纲”范畴,但在面试中能够很好地体现面试者平时的积累,以及对源码的阅读和思考,显然是加分项。

    通过本文的分析,我们看到 this 纷繁多象,确实不容易彻底掌握。

    在我的课程《前端开发核心知识进阶》中我会尽可能系统地进行讲解、说明,例题尽可能地覆盖更多 case。与此同时,大家也要在阅读之外继续进行消化与吸收。只有“记死”,才能“用活”。

    关注前端领域的读者

    欢迎扫码订阅这门课程

    接下来会更新更多大家感兴趣的话题,点击阅读原文,订阅课程,让我们一起进步。

    最新回复(0)