likes
comments
collection
share

undefined 的“七大罪”(自律版)

作者站长头像
站长
· 阅读数 20

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

今天我们来伪科普一下下——uzi 为什么是神?undefined 为什么是坑?)


敏感话题(省流版)

如果说设计模式是最佳实践,那么反模式就是“最渣实践”。

为了避免成为“渣男”,我们有必要了解一些编程的反模式。这些反模式可能会带来挨踢负债(Technical debt,技术负债),将来需要重构代码来还债。

前端冷知识

反模式(Anti-patterns/pitfalls),是指用来解决问题的带有共同性的不良方法。它们已经经过研究并分类,以防止日后重蹈覆辙,并能在研发尚未投产时辨认出来。

undefined 为粒子的反模式包括但不限于——

  1. 禁止重写全局属性,因为不同模式行为不一
  2. 禁止声明 undefined 变量,因为同名局部变量会屏蔽全局属性
  3. 禁止无脑使用 undefined 初始化,因为编程动机不够明确
  4. 尽量不要“光明正大”地使用 undefined,因为“隐性性状”更加鲁棒
  5. 禁止动态修改变量的类型,因为静态编程更好维护
  6. 禁止魔术字面量,因为硬编码有悖 DRY 原则
  7. 禁止使用 ==undefined 指纹识别,因为 null == undefined

懂得都懂,不懂关注,日后再说~


首先是犯下贪婪之罪的“四不像”

地球人都知道,ES5 之前 undefined 可重写,ES5 之后鲁棒只读的 undefined 赋能祂先天免疫一些阴间操作。

举个粒子,当我们尝试重写全局属性时,试试就逝世。

undefined 的“七大罪”(自律版)

猫眼可见,undefined 的内心毫无波动。

虽然但是,相同代码在运行时的不同模式下测评可能出现不同的“四不像”行为:

  • 严格模式禁止赋值,运行时直接“阳了”,抛出异常
  • 非严格模式赋值无效,运行时静默失败

换而言之,非严格模式下即使赋值无效也不会报错,undefined 表面好像被重写了,但其实并没有,其他读码人可能理解出现歧义。

百度百科曾经说过,所谓“四不像”指的是——往往一个设计模型可以暴露不同的接口给用户,不同的接口表现了模型的不同方面。

举一反一,原则上我们禁止重写全局属性,不作死就不会死,规避不同模式运行时的双标行为。


其次是犯下嫉妒之罪的“竞争危害”

地球人都知道,ES3 之前没有 undefined 全局属性,所以会遗留一些颇具时代局限性的最佳实践。

举个粒子,分享一些历史遗留的 undefined 标识符。

undefined 的“七大罪”(自律版)

猫眼可见,undefined 不是保留字,原则上允许祂作为合法的标识符,即使不合理。

举个粒子,当我们尝试重复声明同名变量时,全局属性就会被屏蔽(shadow,遮蔽)。

undefined 的“七大罪”(自律版)

猫眼可见,局部同名变量会屏蔽全局属性,作用域链机制的“竞争危害”会导致默认的 undefined 变量失真。

百度百科曾经说过,所谓“竞争危害”指的是——缺乏预见事件以不同顺序发生的后果。

举一反一,原则上我们禁止重复声明屏蔽全局属性,不要嫉妒全局变量,避免指猫为狗催生 undefined 的“竞争危害”。


然后是犯下暴怒之罪的“万应灵”

地球人都知道,undefined 是 JS(JavaScript)最抽象的元值(metavalue),原则上允许祂作为兼容对象/原始类型的合法初始值。

举个粒子,遇事不决 undefined因为太麻烦就全点防御力了(因为太麻烦就全写 undefined 了)。

undefined 的“七大罪”(自律版)

猫眼可见,一言不合 undefined,但是编程意图并不明确。

变量的命名应该顾名思义,尽量体现值的含义,反之亦然,初始值应该符合变量名的“人设”,避免指猫为狗。

语冰再重新整理自己的偏见后,形成的全新偏见是——当且仅当变量的类型和值同时不明确时,我们才勉为其难地安排 undefined 作为无状态的占位符。

举个粒子,当我们对变量一无所知时,我们才使用 undefined

undefined 的“七大罪”(自律版)

猫眼可见,当且仅当变量的类型未知/类型需要兼容时,我们才按需赋值 undefined

百度百科曾经说过,所谓“万应灵”指的是——一个对象了解的东西太多,或者要做太多的事情,就好像无所不能一样。

举一反一,原则上我们禁止一言不合 undefined,因为 undefined 的无能在于祂无所不能。


再然后是犯下暴食之罪的“屠龙术”

地球人都知道,undefined 不是字面量,这意味着 undefined 变量并不恒等于 undefined 原始值。

举个粒子,当我们使用 undefined 赋值时,不要画蛇添足。

undefined 的“七大罪”(自律版)

猫眼可见,我们推荐直接使用 undefined 的隐性性状,避免“光明正大”地使用 undefined

百度百科曾经说过,所谓“屠龙术”指的是——没有必要的复杂设计。

举一反一,原则上我们禁止冗余的初始赋值,大可不必把饭叫饥,矫枉过正。


接着是犯下色欲的“乱麻球”

地球人都知道,JS 是一门动态类型语言,原则上允许变量的类型和值动态决定。

虽然但是,动态类型并非无类型——当变量的值确定时,祂的类型也确定了。

举个粒子,我们尝试用静态编程来使用动态语言。

undefined 的“七大罪”(自律版)

猫眼可见,值变型不变,赋值看条件。变量具体的初始值尚未尘埃落定,我们可以优先赋值为具体类型的“特殊值”,提前明示读码人变量的类型约束。

百度百科曾经说过,所谓“乱麻球”指的是——系统没有可辨认的结构,就像一团乱麻一样。

举一反一,原则上我们禁止偷懒直接使用 undefined 重置变量,优先静态初始化和赋值,保持类型不变,避免变量偷猫盗狗,代码变成一团乱麻。


还有是犯下懒惰之罪的“硬编码”

大家大抵都通读过阮一峰的《ECMAScript6 标准入门教程》,其中提及的“魔术字符串”就是“魔术字面量”的一种。

《ECMAScript6 标准入门教程》曾经说过,“魔术字符串”指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。

举个粒子,使用魔术字符串/数字的代码可维护性/可读性十分赶人。

undefined 的“七大罪”(自律版)

猫眼可见,魔术字面量存在明显的短板,包括但不限于——

  1. 重复硬编码可能拼写错误,IDE 不会提示,也没有代码补全
  2. 代码耦合度高,一处出错,处处排错纠错,违背 DRY 原则
  3. 编程意图不够直观,你码我猜,谁都不爱

举个粒子,模块化共享常量解耦重构,消除魔术字面量。

undefined 的“七大罪”(自律版)

猫眼可见,优雅得不谈。

举一反一,undefined 也有类似的魔术副作用,我们也可以通过模块化的共享常量来重构。

undefined 的“七大罪”(自律版)

猫眼可见,我们封装了鲁棒的 undefined 共享常量,按需使用即可。

百度百科曾经说过,所谓“硬编码”AKA“写死”,指的是在实现某系统用途上设死该系统的运作环境。

举一反一,原则上我们不推荐偷懒反复地使用魔术字面量,也不推荐直接使用 undefined 全局属性,我们可以重构解耦,规避硬编码的挨踢负债。


最后是犯下傲慢之罪的“反抽象”

MDN 文档曾经说过,undefined 是一个见怪不怪的标识符,碰巧成为全局属性。

换而言之,undefined 没有设计为像 null 一样的字面量,某种意义上成为了现代化前端开发的历史包袱。

你知道的,我们可以通过 globalThis.undefined 来替换 undefined,但吹毛求疵的话,频繁访问全局作用域会降低性能,也不是一种好习惯,因为涉及全局作用域的操作总是让我们在意作用域污染的隐患。

抛开 undefined 自己的历史包袱不谈,undefined 的指纹识别也魔鬼在细节。

举个粒子,因为 Undefined 类型有且仅有一个原始值—— undefined,所以我们既可以通过类型,也可以通过值来识别 undefined

undefined 的“七大罪”(自律版)

猫眼可见,我们可以通过类型判断/值比较来识别 undefined 原始值。

虽然但是,使用“三长”才能避免“两短”——=== 严格相等优于 == 宽松相等,我们要扬长避短。

BTW,虽然对象不存在的属性缺省值(default,默认值)是 undefined,但是这不能用来判断对象的属性所有权。

举个粒子,对象属性值为 undefined 并不意味着对象没有该属性。

undefined 的“七大罪”(自律版)

猫眼可见,禁止盲人摸猫,undefined 并不是判断对象属性所有权的充分必要条件。

百度百科曾经说过,所谓“反抽象”指的是需要的功能并不暴露给用户,导致用户要在较高层次重新实现一些功能。

举一反一,原则上允许我们通过类型/值比较对 undefined 进行指纹识别,但是禁止 ==,使用 === 扬长避短。BTW,原则上不推荐使用 undefined 判断对象属性的所有权。


免责声明

地球人都知道,坏的制度会让好人作恶,好的制度能让坏人从良。

举一反一,坏的代码会让黑客破防,好的代码能让码农内卷。

相信我,你永远可以相信 undefined,只要你不使用祂。

换而言之,任何时候、任何情况下,我们承诺不首先使用核武器undefined)。

CatCAT 曾经说过,关于 undefined 有“撸码十诫”——

第一诫——除了我之外,你不可有别的值。

第二诫——不可为自己冗余赋值。

第三诫——不可妄称 undefined 的名。

第四诫——不可遇事不决 undefined

第五诫——当知书达礼,仅仅知道本文的知识是不行的,还要懂得给语冰彼芯送礼。

第六诫——不可变型,值变型不变,赋值看条件。

第七诫——不可 ==

第八诫——不可万物皆可 undefined

第九诫——不可魔术字面量。

第十诫——不可判断对象属性。

你知道的,代码千万条,优雅第一条,撸码不鲁棒,同事两行泪。

今天我们伪科普一下下 undefined 的反模式和安利了语冰的若干代码洁癖(个人向),即使不是最佳实践,也希望对你有所帮助。

吾乃前端的虔信徒,传播 BUG 的福音。

我是大家的林语冰,我们一期一会,不散不见,掰掰~