Mark24
随笔:Ruby和JavaScript横向对比
导航关联
前言
都是个人思考,欢迎交流和批评。如果我思考的不对请告诉我。
作用域比较
1.JavaScript的作用域
之前做过JavaScript中关于作用域的笔记 JavaScript之理解作用域和作用域链
Javascript除了保留自己的作用域外,内部保留有一个 outer指针总是指向全局作用于,所以Javacript的function 视角,内部永远可以看到外部。词法作用域中对于内部变量都是可见。
2.Ruby的作用域
Ruby在三个关键字 Class\Module\def
存在作用域门,并且彼此隔离。
想要做到JavaScript这种可以穿透作用域的,只能通过 块 方法。因为块方法是一个闭包的实现,内部其实就是携带了所在词法环境的EP(环境指针)指针。
但是Ruby的作用域不如 JavaScript打的开,他只能看到最近的一层。
Ruby可以使用一些技巧比如 扁平作用域、嵌套作用域、共享作用域来实现对作用域的控制。
这样我们可以得到几个结论
- JavaScript的function就自带了闭包。
- JavaScript的作用域很自由没有控制性
- Ruby必须用块才能实现JS中作用域效果
- Ruby有具体的方式来实现对作用域的控制
闭包
如果没有闭包,传值将会要每次通过传参来传递。拥有了闭包,等于函数拥有了自动搜索变量的能力。我们的代码会变得非常短小。
站在作用域和函数功能的角度。其实我可以不负责任的得出几个结论:
JavaScript的 function 其实兼具着很多功能,他相当于:
- 管理创建作用域(函数作用域)
- 起到类构建函数的作用(可以new),模仿类起到封装的作用
- 可以作为纯函数(面向过程的普通函数)
- 可以作为匿名函数(lambda)
- 可以作为隔离名字空间作用(立即执行作用域)
而对应的Ruby
- Module/Class/def 起到创建作用域的作用
- 块 起到 函数+作用域控制的作用
- 块 可以作为lambda 使用
- 类+method 起到封装作用
- Module起到名字空间作用
所以这个角度上,很粗糙的近似,我不负责任的强行关联
项目 | JavaScript | Ruby |
---|---|---|
模块 | 文件为单位 | Module (一个文件还可以放多个) |
类 | function | Class |
方法 | function | method |
匿名函数 | function(){} | lambda/Proc/块 |
作用域 | function提供函数作用域隔离 | Class/Module/def 作用域门 |
穿透作用域 | function自带全局词法作用域指针,全部可见 | 块 只能携带所在的词法层。需要技巧实现多种控制 |
工作图景
经过上面的分析,其实 Ruby的 Proc/lambda/块,相当于 JavaScript真正意义上的工作的函数。 作为逻辑主力。
这样一类比其实非常清晰。如果你把 Ruby的method当成书写逻辑的重点,就会被作用域门封死。
所以这个角度来说,如果JavaScript是围绕着 function编程, Ruby就是围绕 块 才能真正的编程。
这虽然是一个推理,但是实际上不论是Ruby的标准库,还是Ruby的明星应用都传递这给信号证明这是对的。
比如Rake的task暴露的是一个块、Rails的配置暴露的是一个块、Sinatra的Controller留给用户写的还是一个块。
简单归纳下,承认下这个就可以立即把 我的Ruby水平提到我的JavaScript的水平。(水平不高就是敢写)。
JavaScript 的日常工作图景是:
- 函数式程序
只需要用一些函数放在一起执行。
- 类式 以 react组件为例
拥有自己的Class 和内部的 state(实例变量)和方法。
方法和内部数据产生互动。
被实例成为组件。
Ruby的工作图景:
- 函数式工作
那一定是 很多块 组合在一起完成的
- 类式工作
那就是基本类、继承。然后 实例变量和方法。
构造器和方法、包括预留块。这里: Ruby设计模式 里面已经介绍很多了。
- 模块
不同的模块可以用 Module隔离,这里比JavaScript自由可以放很多模块。
补充思考:
- Ruby里面的常量查找方式,看起来就像JS里面的变量,它全部可见,而且具有自动搜索。Ruby的常量还兼具了 先词法作用域查找 再 超类链查找。
- JS直观上更没有约束。Ruby很强烈约束是 —— 方法必须在Class才能执行,这个约束存在之后,Ruby的程序必然的很面向对象。如果想自由表达,那么主要载体就是 Lambda/Proc —— 他们就可以认为是JS里面的function。可以认为灵活的逻辑主力是在这边。
- 主力逻辑落在Proc/Lambda之处,那么Class和method的组合更像是一种为了封装而存在的语法 —— 他的存在是为了以面向对象的形式对现实问题进行建模所用。《Ruby原理剖析》在块那个章节里表达的,我现在的理解很像是 Class、method 提供一个上下文(执行时候的栈帧),具体交换的逻辑会生成 块 去在这个上下文中执行。
相似和差异性
Ruby和JavaScipt的动态性应该是不相上下的。他们都可以被随意更改。JS和Ruby其实最终都是Lisp的近亲。他们有相似的基因。
作用域和查询,JS的查询负担其实更重,他总是遍历,理论上应该更慢。Ruby需要代码层面上完成控制。
除了动态性, Ruby更面向对象,Ruby讲究兼容,并且内部的逻辑相当一致(相对于JavaScript)Ruby的设计更加 Unix Style Friendly。
Ruby的元编程能力更加深入骨髓设计,使用起来友好。
不成熟的结论
- 把 Proc/Lambda 当做JS里面的function,那其实我就和写JS没差了。
- Ruby的方式就是去用面向对象对问题建模,以 Proc/Lambda 的方式提供控制反转。