Hello World!大家好,我是大家的林语冰(挨踢版)~
粉丝质疑
之前肝了一期《Vue 为什么禁用 undefined
》的水文,不幸的是,惨遭道友先质疑、再质疑。
那这里我就简单讲两句:
- 任何编程语言中,某个单词能不能作为标识符,其实是由编译原理和语言规范共同决定的啦(安利哈工大的编译原理,反正我看得头大...)
- 严格模式和
undefined
没有直接关系喔,除非你硬要发生关系
事实证明,很多喵仙人知道严格模式,但没有完全知道,就像祂们对 undefined
一样处于似懂非懂的叠加态。
你知道吗?其实《ES6 标准入门教程》有一一列举严格模式的限制:
如你所见,严格模式真的很机车欸,超多细节还蛮劝退的,背是不可能背的,这辈子都不可能背。(除非你有"超忆症",就当我没说。)
大家连《ES6 标准入门教程》都不认真念吼,一整个被你打败了啦。
不过今天我们要伪科普的是其他东东,尤大劝学,严格模式不会不行。
今日头条(TLDR 省流版)
关于严格模式的若干错误解读,包括但不限于:
- 因为你没写
'use strict'
,所以你没开严格模式 - 精通 ES6 的严格模式是面试加分项
- 严格模式本质是做减法,所以严格模式是草率模式的子集
'use strict';
必须出现在脚本/函数的首行
不幸的是,上述说法都有看不见的 BUG 魔鬼在细节,以上结论其实都是语冰以往被坑的"思想钢印"啦,今天就来一波以身试法反向教学,我超勇的啦。
彼芯到位,干货学会,懂得都懂,不懂 follow。葱葱葱~
尤大改变了世界线
你可能完全不 care 严格模式,反正你会说你从来没主动写过 'use strict'
这样子。
不好意思,你知道吗?尤雨溪先生已经把车门焊死了...
Vite 官网的 troubleshooting 章节是这样讲的,Vite 既无法处理、也不支持运行在草率模式的代码,因为 Vite 使用 ESM 模块,该模块始终使用严格模式。
Vite cannot handle and does not support code that only runs on non-strict mode (sloppy mode). This is because Vite uses ESM and it is always strict mode inside ESM.
简而言之,Vite 能且仅能支持严格模式喔。
所以如果你司的项目不幸使用了 Vite,哦豁,那你已经被严格模式包围了。
Vue 3.0 的版本名就叫做"One Piece",汉化为"航海王",而《航海王》正好有一句台词是这样讲的,时代的齿轮已经被我破坏,自此之后无人再有后路可走。
举一反一,前端工业时代的齿轮已经被尤大破坏,自此之后无人再有草率模式可用了啦。
大家可能还会想"曲线救国",大不了就换 webpack 打包啊,不用 Vite 会怎样啦。我跟你说吼,你可以去瞄一眼 webpack 的打包结果,你猜祂有没有给你开启严格模式呢。
这就是严格模式最涩的地方,祂无处不在,不管你是否显式地使用 'use strict'
,你都可能不知不觉中开启了严格模式。
前端工程化中的优雅降级,很大程度依赖于 babel 生态,Vite/webpack/rollup/... 都集成了 babel 插件,比如可以将 ES6 的新语法优雅降级为 ES5 的旧语法。
就算你/你司特立独行吼,就不用 webpack/Vite 又怎样,你的代码有没有用到 babel 呢?如果有,恭喜你,你可能已经开启严格模式了啦,why?
如你所见,import/export
是 ESM 模块语法,默认就是严格模式。
所以最危险的其实是你可能没有意识到你是在严格模式下写代码。如果你不懂严格模式就啪啪啪一顿操作,那你可能不知道你的代码在搞机掰。
严格模式的设计动机
所以说,严格模式必须要会啦。那严格模式为什么应运而生呢?
因为 ES5 之前存在很多 JS 垃圾语法不科学,但又不能暴力删除,毕竟这又不是猫猫绝育,不能说割蛋就割割蛋,所以就搞了个严格模式来渐进增强和优雅降级。
举个粒子,严格模式禁用 with
语句。
如你所见,with
语句在严格模式会爆炸。
那这里想问一下大家吼,上面这段代码会被解析为以下哪段代码呢?
- 1.
key = value
- 2.
key = obj.value
- 3.
obj.key = value
- 4.
obj.key = obj.value
要我说,3 短 1 长选最长,啊不然咧!那反过来说,3 长 1 短选最短好像也没差啊...这个盲猜思路好像有点猪头欸。
答案是全都对也全都不对,具体的解析有 obj
的属性决定,任何一个平行宇宙有可能发生。
所以说 with
语句真的恶到爆,大家可能没用过呢。但其实 Vue 源码就有涉及,所以我们写不出 Vue 是有原因的。
严格模式不加分
我们要求大家都懂一点严格模式,听起来好像开始卷了。不幸的是,这甚至谈不上内卷,因为严格模式不是加分项,而是敲门砖。
你知道的,ES6 破蛋于 2015 年,2015 - 2017 那几年是 ES6 的主场优势,ES6 还算是你的简历加分项,之后 ES6 就是基本技能了。
反观严格模式,祂甚至比 ES6 还早出现,ES6 都快 10 岁了,而严格模式是 ES5 的特性,根本算不上加分项,所以内卷个机掰啦?如果你不懂严格模式,只能说你 ES6 入门了个寂寞。
所以,真心不建议在简历的加分项写熟悉严格模式,也不要在项目亮点中写精通 ES6。
严格模式不只是做减法
超多卷毛狒狒误会严格模式是草率模式的子集,祂们认为严格模式就是草率模式做减法,比如删除若干奇奇怪怪的语法特性就欧了,不知道你是不是这样子想的?
但其实严格模式其实不是草率模式的子集啦。
MDN 文档是这样子讲的,严格模式是草率模式的限制性变体(restricted variant)。
举个粒子,除了删除若干语法特性,严格模式还可能保留某个特性,只是针对该特性提供新的语义,覆盖其行为。
如你所见,严格模式不会禁用 Function.prototype.apply()
API,也不会废弃 this
关键字,但是会为 this
提供一龙一猪的运行时绑定:
- 严格模式:
this === null
- 草率模式:
this === globalThis
简而言之,严格模式不是通过简单粗暴地做减法就欧了,而是通过"断舍离"创造的,包括但不限于:
- 当断则断的"断":废弃/修复了若干影响 JS 引擎执行性能的语法
- 舍近求远的"舍":禁用若干未来 ES 规范相关的敏感语法
- 离经叛道的"离":将"静默失败"的运行时行为改为"抛出异常"
隐式/显式的严格模式
可执行代码开启严格模式的方式大致有两种喔:
- 显式手动使用
'use strict'
指令开启 - 隐式自动开启
为什么一个平平无奇的 'use strict'
字符串拥有如此神奇的魔力?
因为在不支持 ES5 严格模式的环境中,该指令只会被解释为一个人畜无害的字符串,不会有额外的副作用。而在支持严格模式的环境中,该指令就会自动触发严格模式,这种"双标黑魔法"的兼容性设计不就好棒棒啊!我只想说一个字,perfect!
举个粒子,开启严格模式的部分写法:
除此之外,还有其他不常用的 eval/Function/...
等可执行代码也支持类似的方式。
另一个误区是,'use strict'
必须出现在首行才能生效,大部分情况下是这样子没错啦,但其实也不一定喔。
举个粒子,注释在第一行也不会影响啦。
类型检查的"严格模式"
你知道的啦,TS 本就是 ES6 的超集,所以 TS 也支持严格模式。
其次,TS 的类型检查也可盐可甜,支持严格的类型检查,但不要和 ES6 的严格模式混淆了喔。
ES6 的严格模式是针对语言的语义,TS 的类型严格检查是针对类型推断。
高能总结
草率模式是旧时代的残党,如果你不懂严格模式,新时代前端没有你的船。
- Vite 能且仅能支持严格模式
- 严格模式可以显式/隐式开启
- 严格模式 ES5 破蛋,不是 ES6 的新特性
- 严格模式是断舍离的限制性变体,不是草率模式的严格子集
'use strict';
最好在脚本/函数的首行,但不是必须