JavaScript 的好与坏
May 09, 2023
道格拉斯的观点
JSON 发明者,《JavaScript 语言精粹》作者
观点1
If a feature is sometimes useful and sometimes dangerous and if there is a better option then always use the better option.
如果一个特性有时好用有时危险,还有一个更好的选项,那么我们总是应该使用哪个更好的。
观点2
We are not paid to use every feature of a language. We are paid to write programs that works well and are free of error.
公司雇我们不是为了让我们使用语言的每个特性,而是让我们写出可以用的代码,并且避免错误。
根据以上两个观点,得到结论:我们是不是有可能,只用 JS 好用的部分呢?如果我们坚持使用 JS 好用的部分,我们就可以避免 JS 本身带来的 Bug
保守派之反驳
这个时候,就会有人这么说:
- 为什么 JS 要把那些特性给我们呢?那就是因为觉得我们需要 JS 有这些特性才要给我们的,或者有这么一句话 —— 存在即合理
- JS 有这些特性,肯定是有他一定得理由,那我们为什么要反对去用它呢?
那不得不说说程序员的共识:
- 我们程序员是在不断进化的,我们现在学到的知识是进化了几十年后的效果
- 就像人类一样,人类现在在上小学的时候,都知道地球是圆的(虽然严格来说并不是),但是在过去几千年里,人类都不知道地球是圆的
- 那么程序员也是一样的,现在的程序员在刚入门的时候,就知道面向对象是好的、高级语言是好的等等,这些东西你一入门就知道,但是以前的程序员要不断地进行达成共识
程序员的共识
那么怎么达成的呢?让我们回顾过去 50 年的历史
1960 年代
程序员花了一代人的时间去认同「高级语言是好的」(反方:机器语言效率高)
高级语言就是现在用的 JavaScript、Java、C++、Python、Ruby 等…
但「这些语言是好的」这件事情,在曾经不被认可
他们认为:汇编、机器语言才是最好的,因为省内存、效率高,如果使用高级语言,光是解析这些语言,就要占用一半以上内存,剩下的内存就不够用了(因为 1960 年计算的内存 2MB 就已经算非常大了)
跟随着机器的内存不断提高,并且用了这些语言之后发现很好用,所以就认同了这个观点
1970 年代
程序员花了一代人的时间去认同「goto
是不好的」
因为 goto
会被滥用,所以程序员们达成了共识,所以在很多语言中就尽量少用 goto
(在 JavaScript 中,是不支持 goto
的,虽然有个 goto
半成品:可以在 break
中使用)
对应的就支持 —— 「结构化编程」
一个编程语言只需要支持 3 种结构:子程序
、for 循环
、if
也就是:顺序执行语句
、条件语句
和 循环语句
,只要有这 3 中语句,贝尔梅尔这门编程语言就是完整的
1980 年代
反对以前那种松散的面条式代码
程序员花了一代人的时间去认同「对象是好的」,发展 面向对象
现在 JS 默认是有对象的,但是在很早之前,在 C 语言那个时候,大家都不用对象,这个时候发明 Java 的程序员在那个时候就开始研究设计模式,开始研究面向对象(那个时候 Java 还没出生),把面向对象研究得很成熟之后,Sun 公司才推出了 Java 这门语言
1990 年代
程序员花了 20 年的时间去认同「lambda
表达式是好的」,这件事情在目前估计还没有完全认同
lambda
在 JS 中,lambda
表达式是匿名函数
「匿名函数是个好东西」 这句话如果说给 JS 程序员听,就不会有什么特别感觉,觉得挺好的
而说给 Java、C++ 程序员,他们就不会有跟我们一样的感觉,就会觉得 类
会更好呀,为什么我们要使用 lambda 表达式
呢?
在后面版本,Java、C++、PHP、Python 都加入了 lambda
表达式,不使用之前过于复杂的面向对象的设计,而是用更轻量的匿名函数和闭包的形式来写我们的程序
那些不对的观点
存在即合理
比如 JS 中的:var
、==
代码越短越好
并不完全错误,「无歧义」优于「简洁」
代码虽然写得短,但有可能不同的人有不同的理解,那这样就不好了
例如:
1 | let fn = x => {name: x} |
如果以上代码我这样调用:fn('John')
,很多新手就会以为输出 John
,其实是 undefind
那么如何解决呢?请这么修改
1 | let fn = x => ({name: x}) |
所以,有时候会造成歧义,但是这个歧义不是人造成的,是 JS 造成的
JS 代码中的特性取舍
基本原则:能完成特定功能,并且无歧义、无副作用,这样的特性,优先使用
不要用的 JS 特性
绝对不要用
全局变量(如果有1万个全局变量?)
var
有 Bug,会变量提升;
有副作用,声明后会挂载到 window==
1
[] == 0, "0" == 0, [] != "0"
包装类型 String、Boolean
1
2
3
4
5
6
7var x = new String(false)
if(x) {
console.log('hi')
} else {
console.log('ho')
}会输出
hi
,因为x
是一个对象,JS 中所有的对象都是true
有些人不用
- class、new、this
- 比如喜欢 React Hooks 的开发者
用的人不多,尽量少用
- symbol、generator、iterator
- 反射
一定要用的 JS 特性
===
...
运算符模块
import
、export
let
const
析构赋值
Promise
、await
可以使用的 JS 特性
class
getter
、setter
WeakMap
Proxy
存在问题但可以用
箭头函数
数组 API + Polyfill
感谢阅读,下次见 :)
cd ../