严格模式也能面试?不懂严格模式这辈子都写不出Vue框架!

Hello World!大家好,我是大家的林语冰(挨踢版)~

我们平时使用 ES6 开发大概率是基于严格模式,但除了开发踩坑,其实面试也有可能通过严格模式变着花样坑你。

还有,像 Vue 等开源项目默认也是全局严格模式,但偶尔局部也要用到草率模式的特性,那如何在全局严格模式中当"法外狂徒",局部使用草率模式的语法特性呢?

这也是一个问题。所以今天我们来伪科普一下关于启用/限用/禁用严格模式的冷知识和"黑魔法",葱葱葱~

今日头条(TLDR 省流版)

  • 知识浓度:3 星
  • 作品字数:2_000 字水文
  • 时间成本:260 秒
  1. 面向对象编程的严格模式(阿里88推理题)
  2. Vue 如何在严格模式下也能使用 with 语句呢?
  3. 如何判断全局严格模式?
  4. 如何判断函数局部严格模式?

彼芯到位,全都学会,懂得都懂,不懂 follow!

面向对象编程的严格模式

除了使用 'use strict' 字符串指令显式开启严格模式,诸如 export/import<script type=module></script> 等 ESM 模块语法也会隐式开启严格模式。

举一反一,在 ES6 类语法筑基的面向对象编程中,某些语法也会隐式开启严格模式。

举个粒子,语冰偷偷共享一道据说是阿里88的推理题。

那这道题的问题是,this 绑定是什么鬼物呢?

  • A. 实例对象 cat
  • B. 全局的 globalThis
  • C. cat/globalThis 都有可能
  • D. 其他???

一般而言,this 绑定大约会涉及以下几种场景,包括但不限于:

  • 函数独立调用 fn()
  • 对象实例方法调用 cat.fn()
  • new 实例化构造调用 new Cat
  • call/apply/bind 反射调用 Reflect.apply(fn, null, [])
  • 箭头函数(lambda)词法绑定 () => {}
  • ...

结合题目对号入座,我们科学推理:

  1. 首先,cat.touchFish() 属于方法调用,所以 this 绑定 cat 实例,然后返回 fn
  2. 其次,fn() 属于函数独立调用,所以 this 绑定 globalThis

所以这道题中的 this 绑定可能是 globalThis,因为函数独立调用时 this 默认绑定全局对象 globalThis

然而这并不是正解,实际执行之后会发现 this 绑定其实是 undefined。我们的推理过程问题不大,那为什么结果反而是 undefined

我们知道,在严格模式中,函数独立调用 this 默认绑定 undefined,而在草率模式中则绑定 globalThis

排除一切不可能事件,剩下的说法再玄学,也必是唯一的真相。所以真相只有一个,fn 函数不仅是作为函数独立调用,而且还是在严格模式下调用。

换而言之,上述代码可以转化为以下的等价代码:

如你所见,一旦你的代码中使用了 class 关键字,类区块中的所有语法将在严格模式下执行。

这就是这道题的隐藏考点,类作用域默认能且仅能支持严格模式,你答对了吗?

类似的题目还有结合箭头函数等变体,但解题思路都大同小异,包括但不限于:

禁用/限用严格模式的"黑魔法"

现代化前端开源项目大都基于严格模式开发,但有时确实需要使用草率模式的语法。

举个粒子,严格模式禁用 with 语句,所以在严格模式中使用 with 语句会报错。但是 Vue 的编译器依赖 with 语句实现,那有什么黑魔法可以局部规避严格模式吗?

所以我们写不出 Vue,其实是有原因的。如果不懂启用/禁用/限用严格模式的千层套路,我们这辈子都写不出类似 Vue 的开源框架。

其中一个思路就是"序列化"(这里不是指 JSON 那种序列化)。

举个粒子,with 语句之所以会报错,是因为在严格模式下,JS 引擎编译时就能识别该语法,并抛出静态语法异常。

序列化的思路就是不直接使用 with 语句,而是间接使用,比如把 with 语句变成字符串,然后交给 eval/Function 执行就欧了。

如你所见,with 语句这里不是源码,而是字符串,所以 JS 引擎编译时不会报错,即使是在严格模式下。

需要注意的是,这里 eval 必须使用间接调用,直接调用还是会被全局严格模式捕获。

另外,一些语法并不支持严格模式。

注意,这里的说法是不支持严格模式,而不是不被严格模式支持。

举个粒子,使用了非简单形参的函数局部不允许使用 'use strict' 指令。

如你所见,这种函数开启局部严格模式会报错。

非简单形参包括 ES6 提供的若干新语法特性:

  • 剩余参数
  • 默认参数
  • 解构参数
  • ...

检测全局严格模式

由于相同语法在严格模式会有不同静态语义和运行时行为,所以有时候我们也需要判断严格模式,然后再去 DIY 我们的代码逻辑。

举个粒子,经典笔试题模拟实现一个 Reflect.apply() API 就涉及这种刚需,那么如何去判断当前的全局环境是否开启了严格模式呢?

其中一个思路利用"牛三定律"借力打力,直接写一些严格模式不支持的语法,如果爆炸,说明当前环境开启了严格模式,否则就是草率模式。

举个粒子,函数独立调用时,在严格模式下 this 绑定 undefined,在草率模式下则绑定 globalThis

如你所见,利用函数独立调用的"双标"行为就欧了,但要注意这里不能是箭头函数/顶层作用域的 this,一些 edge cases 会导致判断失真。

检测局部严格模式

我们知道除了全局脚本/ESM 模块的严格模式,还有类区块严格模式和函数局部严格模式等。

有时候可能我们全局是草率模式,但某个函数局部是严格模式,那如何判断该函数开启了严格模式呢?

很可惜,截止本文付梓为止,语冰也未能找到一种完美的解决方案,简直是要逼死强迫症了...

FYI,这里会反向教学一些不完美的解决方案,帮助大家少走弯路。

第一种思路,将函数"序列化",然后判断函数体代码是否包含 'use strict' 指令。

虽然但是,如果函数体代码中含有 'use strict' 的字符串,但如果只是注释呢?我们的判断就会失真。

第二种思路,关于字符串相关的算法设计,优先考虑正则表达式,所以我们可以使用正则精准匹配函数体,并且函数体首行是 'use strict',我们才认为该函数开启了严格模式。

虽然但是,我们之前已经分享过了,'use strict' 不一定要求要出现在首行。所以这种方法也不完美。

第三种思路,我们利用"牛三定律"借力打力,让函数使用严格模式的语法,再观察祂有没有爆炸,但这种方法未必适用于箭头函数等 edge cases。

Anyway,大家有什么大胆的想法/奇奇怪怪的"黑魔法",欢迎在留言区自由言论。

高能总结

  1. 类作用域能且仅能支持严格模式
  2. 限用严格模式语法可以乞灵于 eval 等黑魔法
  3. 判断全局严格模式可以利用"牛三定律"借力打力
  4. 判断函数局部严格模式暂不支持

吾乃前端的虔信徒,传播 BUG 的福音。我是大家的林语冰,我们一期一会,不散不见,掰掰~

相关推荐
天天进步20152 小时前
Vue+Springboot用Websocket实现协同编辑
vue.js·spring boot·websocket
疯狂的沙粒2 小时前
如何在Vue项目中应用TypeScript?应该注意那些点?
前端·vue.js·typescript
小镇程序员3 小时前
vue2 src_Todolist全局总线事件版本
前端·javascript·vue.js
疯狂的沙粒3 小时前
对 TypeScript 中函数如何更好的理解及使用?与 JavaScript 函数有哪些区别?
前端·javascript·typescript
瑞雨溪3 小时前
AJAX的基本使用
前端·javascript·ajax
力透键背3 小时前
display: none和visibility: hidden的区别
开发语言·前端·javascript
程楠楠&M3 小时前
node.js第三方Express 框架
前端·javascript·node.js·express
weiabc3 小时前
学习electron
javascript·学习·electron
想自律的露西西★4 小时前
用el-scrollbar实现滚动条,拖动滚动条可以滚动,但是通过鼠标滑轮却无效
前端·javascript·css·vue.js·elementui·前端框架·html5
白墨阳4 小时前
vue3:瀑布流
前端·javascript·vue.js