最近整理项目模板的时候,发现之前的计算书很丑陋,于是用HTML+CSS+JavaScript三件套重新做了一个。 用这个三件套的原因也很简单,在数学公式排版和页面排版上,现在已经找不到比这个三件套更简单易行的了。 毕竟,MathJax真不是一般的强大。

花了几天的时间,总算是做出来了。又经过几天的琢磨,数次打磨之后,算是比较满意了。

在完成这个计算书页面的过程中,有不少的发现和体会,趁着现在还记得,还是赶紧记录下来吧。

JavaScript 拥有 first-class function

具体来说,JavaScript不但拥有first-class function,而且是自诞生起就是这个样子的。

那么,这个一级函数有什么意义呢?

最简单直接的说法,有了这个它就能算具有函数式编程functional programming的特性了, 这玩意儿可是好多高冷的FP语言的立身之本了。

更进一步来说,JavaScript因为有闭包特性的加持,能够把以函数作为返回值这种做法玩出花来。 相比之下,autolisp虽然是lisp家族的一员,但是,因为它不支持闭包,在拿函数作为返回值的做法, 似乎就没有多少实用性了。

另外,autolisp现有的解析器本身也存在诸多的问题、缺陷或者不便,想要写出来high-level函数, 比如写一个翻转函数形参的函数就是十分地费劲,曾经尝试了很久也没有成功,最后还是在官方论坛某位网友的帮助下才实现的, 目前的翻转函数是这个样子的:

1
2
3
4
5
(defun flip2 (func2 / f) 
  ;; coded by @徐工徐工
  ;; https://95ie.net
  (setq f (eval func2))
  (eval (list 'lambda '(x y) (list f 'y 'x))))

这个函数在大部分函数式编程语言中通常名为 flip ,之所以写成 flip2 完全是因为autolisp的函数形参个数是固定不可变的, flip2 就意味着翻转的是1个binary二元函数。之所以把代码块标注为 lisp,是因为lisp的代码高亮效果基本上是通用的。

JavaScript的bool运算跟lisp很像

在JavaScript里边的 &&|| 运算符,返回的并不是boolean类型的 truefalse,它返回的参与运算的值之一。 比如,33 && 11 返回的是 11 而不是 true,这个做法跟lisp、racket是一模一样的。

它还专门引入了 ?? 运算符,用以实现“非此即彼”的取值效果,避免 || 引起的某些问题。

另外,JavaScript还支持x ? a : b这样的三元运算符,算是c语言比较合格的学生了。

使用对象或者立即执行函数可以实现命名空间的效果

JavaScript不支持命名空间,ES6实现了对module的支持,还有一些其他类型的module实现,不过,在这些出现之前, 避免名称污染实现命名空间效果有几种奇技淫巧,最常用的可能就是立即执行函数。在试用过这种方法之后,发现用起来确实很爽, 再也不必像写autolisp那样添加一大串前缀名了。

严格来说,autolisp可以通过嵌套函数来实现“子函数”、“内部函数”的短名称,只是, 在使用“链接”、“内部符号化”这些编译优化选项时会出现各种问题, 自从不再使用嵌套函数、尽量不使用lambda函数之后,出现编译错误的情况已经是寥寥可数的了。