注册
web

从编程语言的角度,JS 是不是一坨翔?一个来自社区的暴力观点

给前端以福利,给编程以复利。大家好,我是大家的林语冰。


00. 写在前面


毋庸置疑,JS 的历史包袱确实罄竹难书。用朱熹的话说,天不生 ES6,JS 万古如长夜。


就技术细节而言,ES6 之前,JS 保留了若干臭名昭著的反人类设计,包括但不限于:



  • typeof null 的抽象泄露
  • == 的无理要求
  • undefined 不是关键词
  • 其他雷区......

幸运的是,ES5 的“阉割模式”(strict mode)把一大坨 JS 的反人类设计都屏蔽了,后 ES6 时代的 JS 焕然一新。


所以,本期我们就从编程语言的宏观设计来思考,先不纠结 JS 极端情况的技术瑕疵,探讨一下 JS 作为地球上人气最高的编程语言,设计哲学上到底有何魅力?


00-js.png



免责声明:上述统计数据来源于 GitHub 社区,可能存在统计学偏差,仅供粉丝参考。



01. 标准化


编程语言人气排行榜屈居亚军的是 Python,那我们就用 JS 来打败 Python。


根据 MDN 电子书,JS 的核心语言是 ECMAScript,是一门由 ECMA TC39 委员会标准化的编程语言。并不是所有的编程语言都有标准化流程,JS 恰好是“天选之子”,后 ES6 的提案流程也相对稳定,虽然最近突然增加了 stage 2.7,但整体标准化无伤大雅。


值得一提的是,JS 的标准是向下兼容的,用户友好。JS 的大多数技术债务已经诉诸“阉割模式”禁用,而向下兼容则避免了近未来的 ESNext 出现主版本级别的破坏性更新。


举个栗子,ES2024 最新支持的数组分组提案,出于兼容性考虑,提案一度从 Array.prototype.group() 修改为 Object.groupBy()


02-group.png


可以看到,JS 的向下兼容设计正是为了防止和某些遗留代码库产生命名冲突,降低迁移成本。


换而言之,JS 不会像 Python 2 升级 Python 3 那样,让用户承担语言迭代伴生的兼容性税,学习成本和心智负担相对较小。


02. 动态类型


编程语言人气排行榜屈居季军的是 TS,那我们就用 JS 来打败 TS。


JS 和 TS 都是 ECMAScript 的超集,TS 则是 JS 的超集。简而言之,TS ≈ JS + 静态类型系统。


JS 和 TS 区别在于动态类型 vs 静态类型,不能说孰优孰劣,只能说各有千秋。我的个人心证是,静态类型对于工程化生态而言不可或缺,比如 IDE 或 Linting,但对于编程应用则不一定,因为没有静态类型,JS 也能开发 Web App。


03-ts.png


可以看到,因为 TS 是 JS 的超集,所以虽然没有显式的类型注解,上述代码也可作为 TS 代码,只不过 TS 和 JS 类型检查的粒度和时机并不一致。


一个争论点在于,静态类型的编译时检查有利于服务大型项目,但其实在大型项目中,一般会诉诸单元测试保障代码质量和回归测试。严格而言,静态类型之于大型项目的充要条件并不成立。


事实上,剥离静态类型注解的源码,恰恰体现了编程的本质和逻辑,这也是后来的静态类型语言偏爱半自动化的智能类型系统,因为有的类型注解可能是画蛇添足,而诉诸智能的类型推论可以解放程序猿的生产力。


03. 面向对象


编程语言人气排行榜第四名是 Java,那我们就用 JS 来打败 Java。


作为被误解最深的语言,前 ES6 的 JS 有一个普遍的误区:JS 不是面向对象语言,原因在于 ES5 没有 class。


这种“思想钢印”哪里不科学呢?不科学的地方在于,面向对象编程是面向对象,而不是 面向类。换而言之,类不是面向对象编程的充要条件


作为经典的面向对象语言,Java 不同于 C艹,不支持多继承。如果说多继承的 C艹 是“面向对象完备”的,那么能且仅能支持单继承的 Java,其面向对象也一定有不完备的地方,需要诉诸其他机制来弥补。


JS 的面向对象是不同于经典类式继承的原型机制,为什么无类、原型筑基的 JS 也能实现多继承的 C艹 的“面向对象完备”呢?搞懂这个问题,才能深入理解“对象”的本质。


04-oop.png


可以看到,JS 虽然没有类,但也通过神秘机制具备面向对象的三大特征。如果说 JS 不懂类,那么经典面向对象语言可能不懂面向对象编程,只懂“面向类编程”。


JS 虽然全称 JavaScript,但其实和 Java 一龙一猪,原型筑基的 JS 没有类也问题不大。某种意义上,类可以视为 JS 实现面向对象的语法糖。很多人知道封装、继承和多态的面向对象特性,但不知道面向对象的定义和思想,所以才会把类和“面向对象完备”等同起来,认为 JS 不是面向对象的语言。


04. 异步编程


编程语言人气排行榜第五名是 C#,那我们就用 JS 来打败 C#。


一般认为,JS 是一门单线程语言,有且仅有一个主线程。JS 有一个基于事件循环的并发模型,这个模型与 C# 语言等模型一龙一猪。


在 JS 中,当一个函数执行时,只有在它执行完毕后,JS 才会去执行任何其他的代码。换而言之,函数执行不会被抢占,而是“运行至完成”(除了 ES6 的生成器函数)。这与 C 语言不同,在 C 语言中,如果函数在线程中运行,它可能在任何位置被终止,然后在另一个线程中运行其他代码。


单线程的优势在于,大部分情况下,JS 不需要考虑多线程某些让人头大的复杂处理。因为我只会 JS,所以无法详细说明多线程的痛点,比如竞态、死锁、线程间通信(消息、信道、队列)、Actor 模型等。


但 JS 的单线程确实启发了其他支持多线程的语言,比如阮一峰大大的博客提到,Python 的 asyncio 模块只存在一个线程,跟 JS 一样。


05-async.jpg


在异步编程方面,JS 的并发模型其实算是奇葩,因为主流的编程语言都支持多线程模型,所以学习资料可以跨语言互相借鉴,C# 关于多线程的文档就有 10 页,而单线程的 JS 就像非主流的孤勇者,很多异步的理论都用不上,所以使用起来较为简单。


05. 高潮总结


JS 自诞生以来就是一种混合范式的“多面手语言”,这是 JS 二十年来依然元气满满的根本原因。


举个栗子,你可能已经见识过“三位一体”的神奇函数了:


06-fn.png


可以看到,在 ES6 之前,JS 中的函数其实身兼数职,正式由于 JS 是天生支持混合范式导致的。


前 JS 时代的先驱语言部分是单范式语言,比如纯粹的命令式过程语言 C 语言无法直接支持面向对象编程,而 C艹 11、Java 8 等经典面向对象语言则渐进支持函数式编程等。


后 JS 时代的现代编程语言大都直接拥抱混合范式设计,比如 TypeScript 和 Rust 等。作为混合范式语言,JS 是一种原型筑基、动态弱类型的脚本语言,同时支持面向对象编程、函数式编程、异步编程等编程范式或编程风格。


粉丝请注意,你可能偶尔会看到“JS 是一门解释型语言”的说法,其实后 ES6 时代的 JS 已经不再是纯粹的解释型语言了,也可能是 JIT(即时编译)语言,这取决于宿主环境中 JS 引擎或运行时的具体实现。


值得一提的是,混合范式语言的优势在于博采众家之长,有助于塑造攻城狮的开放式编程思维和心智模型;缺陷在于不同于单范式语言,混合范式语言可能支持了某种编程范式,但没有完全支持。(PS:编程范式完备性的判定边界是模糊的,所以偶尔也解读为风格或思维。)


因此,虽然 JS 不像 PHP 一样是地球上最好的语言,但 JS 作为地表人气最高的语言,背后是有深层原因的。


参考文献



作者:前端俱乐部
来源:juejin.cn/post/7392787221097545780

0 个评论

要回复文章请先登录注册