undefined 的“七大罪”(自律版)
Halo Word!大家好,我是大家的林语冰(挨踢版)~
今天我们来伪科普一下下——uzi 为什么是神?(undefined
为什么是坑?)
敏感话题(省流版)
如果说设计模式是最佳实践,那么反模式就是“最渣实践”。
为了避免成为“渣男”,我们有必要了解一些编程的反模式。这些反模式可能会带来挨踢负债(Technical debt,技术负债),将来需要重构代码来还债。
前端冷知识
反模式(Anti-patterns/pitfalls),是指用来解决问题的带有共同性的不良方法。它们已经经过研究并分类,以防止日后重蹈覆辙,并能在研发尚未投产时辨认出来。
以 undefined
为粒子的反模式包括但不限于——
- 禁止重写全局属性,因为不同模式行为不一
- 禁止声明
undefined
变量,因为同名局部变量会屏蔽全局属性 - 禁止无脑使用
undefined
初始化,因为编程动机不够明确 - 尽量不要“光明正大”地使用
undefined
,因为“隐性性状”更加鲁棒 - 禁止动态修改变量的类型,因为静态编程更好维护
- 禁止魔术字面量,因为硬编码有悖 DRY 原则
- 禁止使用
==
对undefined
指纹识别,因为null == undefined
懂得都懂,不懂关注,日后再说~
首先是犯下贪婪之罪的“四不像”
地球人都知道,ES5 之前 undefined
可重写,ES5 之后鲁棒只读的 undefined
赋能祂先天免疫一些阴间操作。
举个粒子,当我们尝试重写全局属性时,试试就逝世。
猫眼可见,undefined
的内心毫无波动。
虽然但是,相同代码在运行时的不同模式下测评可能出现不同的“四不像”行为:
- 严格模式禁止赋值,运行时直接“阳了”,抛出异常
- 非严格模式赋值无效,运行时静默失败
换而言之,非严格模式下即使赋值无效也不会报错,undefined
表面好像被重写了,但其实并没有,其他读码人可能理解出现歧义。
百度百科曾经说过,所谓“四不像”指的是——往往一个设计模型可以暴露不同的接口给用户,不同的接口表现了模型的不同方面。
举一反一,原则上我们禁止重写全局属性,不作死就不会死,规避不同模式运行时的双标行为。
其次是犯下嫉妒之罪的“竞争危害”
地球人都知道,ES3 之前没有 undefined
全局属性,所以会遗留一些颇具时代局限性的最佳实践。
举个粒子,分享一些历史遗留的 undefined
标识符。
猫眼可见,undefined
不是保留字,原则上允许祂作为合法的标识符,即使不合理。
举个粒子,当我们尝试重复声明同名变量时,全局属性就会被屏蔽(shadow,遮蔽)。
猫眼可见,局部同名变量会屏蔽全局属性,作用域链机制的“竞争危害”会导致默认的 undefined
变量失真。
百度百科曾经说过,所谓“竞争危害”指的是——缺乏预见事件以不同顺序发生的后果。
举一反一,原则上我们禁止重复声明屏蔽全局属性,不要嫉妒全局变量,避免指猫为狗催生 undefined
的“竞争危害”。
然后是犯下暴怒之罪的“万应灵”
地球人都知道,undefined
是 JS(JavaScript)最抽象的元值(metavalue),原则上允许祂作为兼容对象/原始类型的合法初始值。
举个粒子,遇事不决 undefined
,因为太麻烦就全点防御力了(因为太麻烦就全写 undefined
了)。
猫眼可见,一言不合 undefined
,但是编程意图并不明确。
变量的命名应该顾名思义,尽量体现值的含义,反之亦然,初始值应该符合变量名的“人设”,避免指猫为狗。
语冰再重新整理自己的偏见后,形成的全新偏见是——当且仅当变量的类型和值同时不明确时,我们才勉为其难地安排 undefined
作为无状态的占位符。
举个粒子,当我们对变量一无所知时,我们才使用 undefined
。
猫眼可见,当且仅当变量的类型未知/类型需要兼容时,我们才按需赋值 undefined
。
百度百科曾经说过,所谓“万应灵”指的是——一个对象了解的东西太多,或者要做太多的事情,就好像无所不能一样。
举一反一,原则上我们禁止一言不合 undefined
,因为 undefined
的无能在于祂无所不能。
再然后是犯下暴食之罪的“屠龙术”
地球人都知道,undefined
不是字面量,这意味着 undefined
变量并不恒等于 undefined
原始值。
举个粒子,当我们使用 undefined
赋值时,不要画蛇添足。
猫眼可见,我们推荐直接使用 undefined
的隐性性状,避免“光明正大”地使用 undefined
。
百度百科曾经说过,所谓“屠龙术”指的是——没有必要的复杂设计。
举一反一,原则上我们禁止冗余的初始赋值,大可不必把饭叫饥,矫枉过正。
接着是犯下色欲的“乱麻球”
地球人都知道,JS 是一门动态类型语言,原则上允许变量的类型和值动态决定。
虽然但是,动态类型并非无类型——当变量的值确定时,祂的类型也确定了。
举个粒子,我们尝试用静态编程来使用动态语言。
猫眼可见,值变型不变,赋值看条件。变量具体的初始值尚未尘埃落定,我们可以优先赋值为具体类型的“特殊值”,提前明示读码人变量的类型约束。
百度百科曾经说过,所谓“乱麻球”指的是——系统没有可辨认的结构,就像一团乱麻一样。
举一反一,原则上我们禁止偷懒直接使用 undefined
重置变量,优先静态初始化和赋值,保持类型不变,避免变量偷猫盗狗,代码变成一团乱麻。
还有是犯下懒惰之罪的“硬编码”
大家大抵都通读过阮一峰的《ECMAScript6 标准入门教程》,其中提及的“魔术字符串”就是“魔术字面量”的一种。
《ECMAScript6 标准入门教程》曾经说过,“魔术字符串”指的是,在代码之中多次出现、与代码形成强耦合的某一个具体的字符串或者数值。风格良好的代码,应该尽量消除魔术字符串,改由含义清晰的变量代替。
举个粒子,使用魔术字符串/数字的代码可维护性/可读性十分赶人。
猫眼可见,魔术字面量存在明显的短板,包括但不限于——
- 重复硬编码可能拼写错误,IDE 不会提示,也没有代码补全
- 代码耦合度高,一处出错,处处排错纠错,违背 DRY 原则
- 编程意图不够直观,你码我猜,谁都不爱
举个粒子,模块化共享常量解耦重构,消除魔术字面量。
猫眼可见,优雅得不谈。
举一反一,undefined
也有类似的魔术副作用,我们也可以通过模块化的共享常量来重构。
猫眼可见,我们封装了鲁棒的 undefined
共享常量,按需使用即可。
百度百科曾经说过,所谓“硬编码”AKA“写死”,指的是在实现某系统用途上设死该系统的运作环境。
举一反一,原则上我们不推荐偷懒反复地使用魔术字面量,也不推荐直接使用 undefined
全局属性,我们可以重构解耦,规避硬编码的挨踢负债。
最后是犯下傲慢之罪的“反抽象”
MDN 文档曾经说过,undefined
是一个见怪不怪的标识符,碰巧成为全局属性。
换而言之,undefined
没有设计为像 null
一样的字面量,某种意义上成为了现代化前端开发的历史包袱。
你知道的,我们可以通过 globalThis.undefined
来替换 undefined
,但吹毛求疵的话,频繁访问全局作用域会降低性能,也不是一种好习惯,因为涉及全局作用域的操作总是让我们在意作用域污染的隐患。
抛开 undefined
自己的历史包袱不谈,undefined
的指纹识别也魔鬼在细节。
举个粒子,因为 Undefined 类型有且仅有一个原始值—— undefined
,所以我们既可以通过类型,也可以通过值来识别 undefined
。
猫眼可见,我们可以通过类型判断/值比较来识别 undefined
原始值。
虽然但是,使用“三长”才能避免“两短”——===
严格相等优于 ==
宽松相等,我们要扬长避短。
BTW,虽然对象不存在的属性缺省值(default,默认值)是 undefined
,但是这不能用来判断对象的属性所有权。
举个粒子,对象属性值为 undefined
并不意味着对象没有该属性。
猫眼可见,禁止盲人摸猫,undefined
并不是判断对象属性所有权的充分必要条件。
百度百科曾经说过,所谓“反抽象”指的是需要的功能并不暴露给用户,导致用户要在较高层次重新实现一些功能。
举一反一,原则上允许我们通过类型/值比较对 undefined
进行指纹识别,但是禁止 ==
,使用 ===
扬长避短。BTW,原则上不推荐使用 undefined
判断对象属性的所有权。
免责声明
地球人都知道,坏的制度会让好人作恶,好的制度能让坏人从良。
举一反一,坏的代码会让黑客破防,好的代码能让码农内卷。
相信我,你永远可以相信 undefined
,只要你不使用祂。
换而言之,任何时候、任何情况下,我们承诺不首先使用核武器(undefined
)。
CatCAT 曾经说过,关于 undefined
有“撸码十诫”——
第一诫——除了我之外,你不可有别的值。
第二诫——不可为自己冗余赋值。
第三诫——不可妄称 undefined
的名。
第四诫——不可遇事不决 undefined
。
第五诫——当知书达礼,仅仅知道本文的知识是不行的,还要懂得给语冰彼芯送礼。
第六诫——不可变型,值变型不变,赋值看条件。
第七诫——不可 ==
。
第八诫——不可万物皆可 undefined
。
第九诫——不可魔术字面量。
第十诫——不可判断对象属性。
你知道的,代码千万条,优雅第一条,撸码不鲁棒,同事两行泪。
今天我们伪科普一下下 undefined
的反模式和安利了语冰的若干代码洁癖(个人向),即使不是最佳实践,也希望对你有所帮助。
吾乃前端的虔信徒,传播 BUG 的福音。
我是大家的林语冰,我们一期一会,不散不见,掰掰~
转载自:https://juejin.cn/post/7245169313242284088