随笔:Ruby和JavaScript横向对比

导航关联

Ruby特性和实验分析汇总

前言

都是个人思考,欢迎交流和批评。如果我思考的不对请告诉我。

作用域比较

1.JavaScript的作用域

之前做过JavaScript中关于作用域的笔记 JavaScript之理解作用域和作用域链

Javascript除了保留自己的作用域外,内部保留有一个 outer指针总是指向全局作用于,所以Javacript的function 视角,内部永远可以看到外部。词法作用域中对于内部变量都是可见。

2.Ruby的作用域

Ruby在三个关键字 Class\Module\def 存在作用域门,并且彼此隔离。

想要做到JavaScript这种可以穿透作用域的,只能通过 块 方法。因为块方法是一个闭包的实现,内部其实就是携带了所在词法环境的EP(环境指针)指针。

但是Ruby的作用域不如 JavaScript打的开,他只能看到最近的一层。

Ruby可以使用一些技巧比如 扁平作用域、嵌套作用域、共享作用域来实现对作用域的控制。

这样我们可以得到几个结论

  1. JavaScript的function就自带了闭包。
  2. JavaScript的作用域很自由没有控制性
  3. Ruby必须用块才能实现JS中作用域效果
  4. Ruby有具体的方式来实现对作用域的控制

闭包

如果没有闭包,传值将会要每次通过传参来传递。拥有了闭包,等于函数拥有了自动搜索变量的能力。我们的代码会变得非常短小。

站在作用域和函数功能的角度。其实我可以不负责任的得出几个结论:

JavaScript的 function 其实兼具着很多功能,他相当于:

  1. 管理创建作用域(函数作用域)
  2. 起到类构建函数的作用(可以new),模仿类起到封装的作用
  3. 可以作为纯函数(面向过程的普通函数)
  4. 可以作为匿名函数(lambda)
  5. 可以作为隔离名字空间作用(立即执行作用域)

而对应的Ruby

  1. Module/Class/def 起到创建作用域的作用
  2. 块 起到 函数+作用域控制的作用
  3. 块 可以作为lambda 使用
  4. 类+method 起到封装作用
  5. 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 的日常工作图景是:

  1. 函数式程序

只需要用一些函数放在一起执行。

  1. 类式 以 react组件为例

拥有自己的Class 和内部的 state(实例变量)和方法。

方法和内部数据产生互动。

被实例成为组件。

Ruby的工作图景:

  1. 函数式工作

那一定是 很多块 组合在一起完成的

  1. 类式工作

那就是基本类、继承。然后 实例变量和方法。

构造器和方法、包括预留块。这里: Ruby设计模式 里面已经介绍很多了。

  1. 模块

不同的模块可以用 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 的方式提供控制反转。

Mark24

Everything can Mix.