归零至零 - 第2幕

在第二篇文章中,我们将逐步介绍实际的ClojureScript源代码源代码可以在上找到GitHub上

注意:我强烈建议你阅读上一篇文章首先,如果你还没有这样做。


ClojureScript 101

在我们深入研究之前,我们将看看ClojureScript的哲学。

由于ClojureScript是一种Lisp方言,它可以消除您从其他编程语言中可能知道的大部分语法这使得它非常简单 - 但它起初看起来很陌生。

(+ 1 1)

这个表达式(也称为S表达式,简称为象征性的表达)有价值2每个表达式都有一个值括号定义其范围基本上,一切在ClojureScript中归结为这个简单的形式:

(函数param1 param2 ..paramN)

表达式中的第一个元素是函数位置,其他元素是其参数这就是所谓的前缀表示法,与之相反代数符号 1 + 1来自C语言。

当然,表达式也可以嵌套:

(println( -  10(* 2 5)))

此表达式将打印出来0因为表达式是由内而外评估的但有趣的是,它的价值在于以来的println只有副作用并且没有返回有意义的值。

注意+的println实际上只是评估值的符号,在这种情况下是函数它们与这方面的常数相似。

有三种类型的值可以在函数位置:

  • 一个功能,就像的println要么+
  • 一种特殊的形式,内置“原始”之类的如果FN高清
  • 一个宏,运行的函数编译时间

关于宏的另一件事:它们是扩展语言和转换代码的一种非常强大的方法例如,函数的所有参数必须先进行评估才能执行 - 但是在这种情况下(和(fn ...)(fn ...))we don't want to evaluate the second parameter if the first one is already false! Good thing是一个宏:它以一种懒惰地执行每个参数的方式转换代码,并且函数尽可能早地返回。

但足够关于宏现在我们将继续浏览todo应用程序的源代码。

第一步

我们的应用程序包含三个ClojureScript源文件:app.cljsitem.cljsutils.cljs让我们开始吧为了感受ClojureScript,我们先看看最小的文件:utils.cljs

;; utils.cljs, part #1
(ns todomvc.utils
  (:require [cljs.reader :as reader])
  (:import [goog.ui IdGenerator]))

在第一行中,通过指定文件的命名空间NS每个ClojureScript文件都需要定义一个唯一的命名空间,todomvc.utils在这种情况下这可以防止名称冲突,并与Google Closure的模块概念很好地集成注意:命名空间与文件路径匹配并不是巧合(todomvc / utils的) - 必须的。

在第二行中,外部ClojureScript命名空间cljs.reader载满了:要求它被命名读者通过要求:如并且可以在整个文件中通过此别名引用。

在第三行,:进口加载模块IdGenerator来自命名空间goog.ui谷歌闭包库与众不同:要求是我们加载特定的元素,而不是命名空间,以便通过名称引用它们。

注意:以...开头的单词是关键字它们就像符号 - 但只是评估自己而不是任意值。

;; utils.cljs, part #2
(defn pluralize [n word]
  (if (== n 1)
    word                ;; 'true'-block
    (str word "s")))    ;; 'false'-block

DEFN定义一个名为的函数变复数有两个参数:ñ在身体里,如果返回原始单词时ñ等于1 - 否则是附加了字符's'的新字符串

注意DEFN只是用于定义匿名函数的快捷方式FN并将其绑定到符号高清

;; utils.cljs, part #3
(defn now []
  (js/Date.))

现在是一个没有任何参数的函数它返回一个新的JavaScript实例日期宾语Since it is a native JavaScript object the prefixJS /必须用来访问JS命名空间。

注意:不起眼负责调用对象的构造函数,比如在JavaScript中。

;; utils.cljs, part #4
(defn guid []
  (.getNextUniqueId (.getInstance IdGenerator)))

GUID使用Closure库IdGenerator返回一个新的唯一ID它还展示了如何在JavaScript对象上调用方法:(.methodName jsObject),请注意在开始表达式转化为IdGenerator.getInstance()。getNextUniqueId()在JavaScript中。

;; utils.cljs, part #5
(defn hidden [is-hidden]
  (if is-hidden
    #js {:display "none"}
    #js {}))

返回JavaScript对象{display:“none”}当参数是隐藏是真的如您所见,返回本机JavaScript对象使用#js {...}元素在键/值对中定义,没有任何特殊字符,如

注意:在ClojureScript中都没有骆驼香烟盒也不snake_case使用,但冲分隔小写

;; utils.cljs, part #6
(defn store
  ([ns] (store ns nil))    ;; 1 parameter
  ([ns edn]                ;; 2 parameters
    (if-not (nil? edn)
      (.setItem js/localStorage ns (str edn))
      (let [s (.getItem js/localStorage ns)]
        (if-not (nil? s)
          (reader/read-string s)
          [])))))

商店从浏览器的本地存储读取数据并将数据写入浏览器的本地存储它包含许多有趣的新事物。

首先,它是一个多元功能这意味着它允许多个参数,[NS][ns edn]在这种情况下它类似于其他语言的函数重载常见用例是为参数提供默认值在这里使用如果没有另外指定,则为第二个参数。

其次,我们看到了一些新的功能。如果不显然是被否定的版本如果零?(最佳做法是在函数末尾使用布尔返回类型设置'?'后缀)检查提供的值是否等于(与...相同空值在JavaScript中)。允许在本地将符号绑定到值,类似于受限制高清: It starts with a vector of bindings, pairs of symbol/value, and concludes with a body of expressions在这里它绑定小号到本地存储访问的结果。

第三,它对ClojureScript数据结构进行序列化和反序列化:文本结果(str edn)写入本地存储.setItem并从本地存储中读取.getItem- 反序列化(读者/读字符串s)来自读者早期加载的命名空

注意: EDN可扩展的数据表示法)就像JSON的扩展版本,还有一些额外的好处,比如非字符串映射键,集合和标签。


这就是现在在第3幕我们将详细介绍Om特有的代码。

与此同时,如果你想了解更多关于ClojureScript的信息,我全心全意地推荐Light Table教程来自Om的创造者David Nolen。


评论由Disqus