├── README.md
├── README.zh.md
└── img
├── calls.png
├── cljs.png
└── sublime-cljs-syntax.png
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | > Translations: [中文](README.zh.md).
4 |
5 | > __If you just wanna try something__, check out the [interactive tutorial](http://chimeces.com/cljs-browser-repl/).
6 |
7 | Hello, this is my attempt at a very concise guide to ClojureScript's syntax!
8 | ClojureScript is a Lisp dialect for front-end web development. It compiles to
9 | JavaScript for use in the browser.
10 |
11 | ClojureScript is fundamentally different from JavaScript and other
12 | compile-to-JS languages like Dart, CoffeeScript, and TypeScript. It uses a
13 | more powerful yet simpler syntax. There are other differences not related
14 | to syntax, such as default immutability to combat the "new spaghetti code"
15 | that is mutatable stateful objects, and sane state management allowing language-level data-binding.
16 |
17 | I believe that ClojureScript's largest barrier to entry for beginners is
18 | probably the foreign nature of its syntax. I hope to explain it as plainly and
19 | succinctly as possible with this guide.
20 |
21 | > __Also__, check out [Parinfer] if you want a simpler way to manage parentheses in ClojureScript.
22 |
23 | [Parinfer]:http://shaunlebron.github.io/parinfer/
24 |
25 | ## Syntax
26 |
27 | There is __literal data__:
28 |
29 | ```clj
30 | ; number
31 | 1.23
32 |
33 | ; string
34 | "foo"
35 |
36 | ; keyword (like strings, but used as map keys)
37 | :foo
38 |
39 | ; vector (array)
40 | [:bar 3.14 "hello"]
41 |
42 | ; map (associative array)
43 | {:msg "hello" :pi 3.14 :primes [2 3 5 7 11 13]}
44 |
45 | ; set (distinct elements)
46 | #{:bar 3.14 "hello"}
47 | ```
48 |
49 | And there is __symbolic data__:
50 |
51 | ```clj
52 | ; symbol (represents a named value)
53 | foo
54 |
55 | ; list (represents a "call")
56 | (foo :bar 3.14)
57 | ```
58 |
59 | #### Evaluation
60 |
61 | ClojureScript can evaluate data to create a new "value" from it.
62 |
63 | 1. Literal data evaluates to itself, of course:
64 |
65 | ```clj
66 | 1.23 ; => 1.23
67 | "foo" ; => "foo"
68 | [:bar 3.14 "hello"] ; => [:bar 3.14 "hello"]
69 | ```
70 |
71 | 1. A __symbol__ evaluates to the value bound to it:
72 |
73 | ```clj
74 | foo ; => 3
75 | ```
76 |
77 | 1. A __list__ evaluates to the return value of a "call".
78 |
79 | ```clj
80 | (+ 1 2 3) ; => 6
81 | (= 1 2) ; => false
82 | (if true "y" "n") ; => "y"
83 | ```
84 |
85 | #### Calls
86 |
87 | If the first element of a list is a __function__, then the rest of the elements
88 | are evaluated and passed to it ([prefix notation](http://en.wikipedia.org/wiki/Polish_notation)).
89 |
90 | ```clj
91 | ; String concatenate function
92 | (str "Hello " "World") ; => "Hello World"
93 |
94 | ; Arithmetic functions
95 | (= a b) ; equality (true or false)
96 | (+ a b) ; sum
97 | (- a b) ; difference
98 | (* a b c) ; product
99 | (< a b c) ; true if a < b < c
100 |
101 | ; Evaluation Steps
102 | (+ k (* 2 4)) ; assume k evalutes to 3
103 | (+ 3 (* 2 4)) ; (* 2 4) evaluates to 8
104 | (+ 3 8) ; (+ 3 8) evalutes to 11
105 | 11
106 | ```
107 |
108 | If the first element of a list is one of the language's few __special forms__,
109 | then the rest of the elements are passed to it unevaluated. (There are only [22
110 | special forms](https://clojure.org/reference/special_forms).)
111 |
112 | ```clj
113 | (if (= a b c) ; <-- determines if a=b=c
114 | (foo 1) ; <-- only evaluated if true
115 | (bar 2) ; <-- only evaluated if false
116 | )
117 |
118 | ; define k as 3
119 | (def k 3) ; <-- notice that k is not evaluated here
120 | ; (def needs the symbol k, not its value)
121 |
122 | ; make a greeting function
123 | (fn [username] ; <-- expected parameters vector
124 | (str "Hello " username))
125 |
126 | ; oops, give the function a name
127 | (def greet (fn [username]
128 | (str "Hello " username)))
129 |
130 | (greet "Bob") ; => "Hello Bob"
131 | ```
132 |
133 | If the first element of a list is a __macro__, then the rest of the elements
134 | are passed to it unevaluated, but the resulting value of the call is evaluated.
135 | Let's illustrate that difference with the following diagram:
136 |
137 | 
138 |
139 | This difference in evaluation allows macros to act as code-generating
140 | functions. For example, the `defn` macro expands to `def` and `fn`, as we used
141 | separately in a previous example:
142 |
143 | ```clj
144 | ; create a named function using the defn macro
145 | (defn greet [username]
146 | (str "Hello " username))
147 |
148 | ; the definition for the defn macro (over-simplified)
149 | (defmacro defn [name args body]
150 | `(def ~name (fn ~args ~body)))
151 | ```
152 |
153 | __App developers rarely need to create their own macros__, but it is an
154 | indispensible tool for the library developer to give app developers the full
155 | flexibility of the language.
156 |
157 | #### Simple substitutions
158 |
159 | There are a few [macro characters](http://clojure.org/reader#The%20Reader--Macro%20characters) that help make the language succinct
160 | by performing simple substitutions (not full macros):
161 |
162 | ```clj
163 | ; short-hand for creating a simple function:
164 | ; #(...) => (fn [args] (...))
165 |
166 | #(* 3 %) ; => (fn [x] (* 3 x))
167 |
168 | #(* 3 (+ %1 %2)) ; => (fn [x y] (* 3 (+ x y)))
169 | ```
170 |
171 | ## That's it for Syntax
172 |
173 | You need to know more than syntax to be proficient in a language, of course.
174 | But you should now know enough to be comfortable looking around at examples and
175 | reasoning about how data is being evaluated and passed around:
176 |
177 | ```clj
178 | ; printing to the javascript console
179 | (js/console.log "Hello World!")
180 |
181 | ; creating local bindings (constants)
182 | (let [a (+ 1 2)
183 | b (* 2 3)]
184 | (js/console.log "The value of a is" a)
185 | (js/console.log "The value of b is" b))
186 |
187 | ; generate a sequence of numbers
188 | (range 4) ; => (0 1 2 3)
189 |
190 | ; generate first four multiples of 3
191 | (map #(* % 3) (range 4)) ;=> (0 3 6 9)
192 |
193 | ; count elements in a sequence
194 | (count "Bob") ; => 3
195 | (count [4 5 2 3]) ; => 4
196 |
197 | ; select three letter names from a list
198 | (def names ["Bob" "David" "Sue"])
199 | (filter #(= (count %) 3) names) ; => ("Bob" "Sue")
200 | ```
201 |
202 | (Don't worry about getting lost in parentheses. All modern text editors will
203 | highlight the corresponding ones and will indent your code automatically for
204 | readability, as is standard in every other language.)
205 |
206 | ## ClojureScript vs JSX in HTML templating
207 |
208 | See [Jumping from HTML to ClojureScript](https://github.com/shaunlebron/jumping-from-html-to-clojurescript) to see how ClojureScript's syntax solves the verbosity/flexibility problems faced in the JS community by [JSX].
209 |
210 | [Jumping from HTML to ClojureScript]:https://github.com/shaunlebron/jumping-from-html-to-clojurescript
211 | [JSX]:https://facebook.github.io/react/docs/jsx-in-depth.html
212 |
213 | ## A complete reference
214 |
215 | The syntax section of the [ClojureScript API reference] is a comprehensive look at
216 | the possible syntax forms and even shows the source code for how each are read/parsed.
217 |
218 | [syntax section]:https://github.com/cljsinfo/cljs-api-docs/blob/catalog/INDEX.md#syntax
219 | [ClojureScript API reference]:http://cljs.github.io/api
220 |
221 | ## Useful Resources
222 |
223 | Here are the resources and steps that I took while learning ClojureScript.
224 | (Most resources covering Clojure also apply to ClojureScript, since they
225 | share a significant subset with each other.)
226 |
227 | 1. Reading through the [ClojureScript Wiki](https://github.com/clojure/clojurescript/wiki)
228 | 1. Reading the book [ClojureScript Up and Running](http://ns.synrc.com/publications/cat/Functional%20Languages/Clojure/Oreilly.ClojureScript.Up.and.Running.Oct.2012.pdf)
229 | 1. Reading the book [Clojure Programming](http://bit.ly/clojurebook)
230 | 1. Doing [ClojureScript Koans](http://clojurescriptkoans.com)
231 | 1. Reading [Clojure Style Guide](https://github.com/bbatsov/clojure-style-guide)
232 | 1. Reading [Clojure Programming By Example](http://en.wikibooks.org/wiki/Clojure_Programming/By_Example)
233 | 1. Reading [Clojure Functional Programming](http://clojure.org/functional_programming)
234 | 1. Thumbing through [Clojure Core API](http://clojure.github.io/clojure/clojure.core-api.html)
235 | 1. Reading [ClojureScript - Differences from Clojure - Host Interop](https://github.com/clojure/clojurescript/wiki/Differences-from-Clojure#wiki-host-interop) for accessing javascript properties like `(.-Infinity js/window)` and functions like `(.sqrt js/Math 25)`.
236 | 1. Reading [JavaScript to ClojureScript synonyms](http://kanaka.github.io/clojurescript/web/synonym.html)
237 | 1. Experimenting in `lein repl` for Clojure REPL.
238 | 1. Experimenting in for ClojureScript REPL with a browser context.
239 | 1. Reading docstrings of functions I encounter with `(doc )` in REPL.
240 | 1. [Miscellaneous ClojureScript things to know](https://github.com/shaunlebron/ClojureSheet#clojurescript-stuff)
241 |
242 |
--------------------------------------------------------------------------------
/README.zh.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | > __如果你只是想试试__, 可以看看这个[交互式教程](http://chimeces.com/cljs-browser-repl/).
4 |
5 | Hello, 我在尝试给 ClojureScript 语法写一份简明的教程!
6 | ClojureScript 是一门适用于 Web 前端开发的 Lisp 方言, 它被编译到 JavaScript 在浏览器中使用.
7 |
8 | ClojureScript 在根本上就和 JavaScript 和其他诸如 Dart, CoffeeScript 和 TypeScript 之类的编译到 JavaScript 的语言不一样.
9 | 它使用了更强大而简单的语法. 也有一些其他一些语法之外的区别,
10 | 比如说默认采用不可变性, 用来解决状态可变的对象造成"新的意面式代码",
11 | 同时提供正常的状态管理功能用来实现语言级别的数据绑定.
12 |
13 | 我相信对于新手来说 ClojureScript 最大的障碍在于他令人感到陌生的语法.
14 | 在这份教程里, 我希望能尽可能清晰而简明地说明它.
15 |
16 | > __同时__, 如果你需要为 ClojureScript 找一个更简单的管理括号的方案, 请了解一下 [Parinfer].
17 |
18 | [Parinfer]:http://shaunlebron.github.io/parinfer/
19 |
20 | ## 语法
21 |
22 | 这是 __literal data(字面量数据)__:
23 |
24 | ```clj
25 | ; number(数字)
26 | 1.23
27 |
28 | ; string(字符串)
29 | "foo"
30 |
31 | ; keyword(关键字, 就像字符串, 但是用于 map 的键)
32 | :foo
33 |
34 | ; vector(向量, 或者说数组, array)
35 | [:bar 3.14 "hello"]
36 |
37 | ; map(关联数组, associative array)
38 | {:msg "hello" :pi 3.14 :primes [2 3 5 7 11 13]}
39 |
40 | ; set(distinct elements, 元素唯一)
41 | #{:bar 3.14 "hello"}
42 | ```
43 |
44 | 还有 __symbolic data(符号化数据)__:
45 |
46 | ```clj
47 | ; symbol(符号, 表示一个有名字的值)
48 | foo
49 |
50 | ; list(链表, 表示一次"调用")
51 | (foo :bar 3.14)
52 | ```
53 |
54 | #### 求值
55 |
56 | ClojureScript 可以对数据求值从而创建出新的"值".
57 |
58 | 1. 字面量数据求值之后得到自身, 显然地:
59 |
60 | ```clj
61 | 1.23 ; => 1.23
62 | "foo" ; => "foo"
63 | [:bar 3.14 "hello"] ; => [:bar 3.14 "hello"]
64 | ```
65 |
66 | 1. __符号__ 求值之后得到绑定在上面的数值:
67 |
68 | ```clj
69 | foo ; => 3
70 | ```
71 |
72 | 1. __list__ 求值之后得到"调用"的结果.
73 |
74 | ```clj
75 | (+ 1 2 3) ; => 6
76 | (= 1 2) ; => false
77 | (if true "y" "n") ; => "y"
78 | ```
79 |
80 | #### 调用
81 |
82 | 如果列表的第一个元素是一个 __函数__, 那么其余元素会被求值并传给它 ([prefix notation](http://en.wikipedia.org/wiki/Polish_notation)).
83 |
84 | ```clj
85 | ; 字符串合并函数
86 | (str "Hello " "World") ; => "Hello World"
87 |
88 | ; 算术函数
89 | (= a b) ; 等式(true 或者 false)
90 | (+ a b) ; 求和
91 | (- a b) ; 求差
92 | (* a b c) ; 求积
93 | (< a b c) ; true if a < b < c
94 |
95 | ; 求值步骤
96 | (+ k (* 2 4)) ; 这里假设 k 求值得到 3
97 | (+ 3 (* 2 4)) ; (* 2 4) 求值得到 8
98 | (+ 3 8) ; (+ 3 8) 求值得到 11
99 | 11
100 | ```
101 |
102 | 如果列表的第一个元素是一个 __特殊形式(Special Form)__, 那么其余元素传递给它时不做求值.
103 | (总共有 [22 的特殊形式](https://clojure.org/reference/special_forms).)
104 |
105 | ```clj
106 | (if (= a b c) ; <-- 判断是否 a=b=c
107 | (foo 1) ; <-- 只在 true 的时候求值
108 | (bar 2) ; <-- 只在 false 的时候求值
109 | )
110 |
111 | ; 定义(define) k 为 3
112 | (def k 3) ; <-- 注意这个 k 不会被求值
113 | ; (def 需要 k 这个符号, 而不是它的值)
114 |
115 | ; 创建一个打招呼的函数
116 | (fn [username] ; <-- 所期望的参数向量
117 | (str "Hello " username))
118 |
119 | ; 哦对了,给这个函数取个名字
120 | (def greet (fn [username]
121 | (str "Hello " username)))
122 |
123 | (greet "Bob") ; => "Hello Bob"
124 | ```
125 |
126 | 如果列表的第一个元素是个 __Macro__, 那么其余元素传给它时不做求值,
127 | 但是调用之后的结果是经过求值的. 用下面这个示意图来说明它们的区别:
128 |
129 | 
130 |
131 | 求值过程上的区别使得 Macro 可以作为生成代码的函数使用.
132 | 比如 `defn` 这个 Macro 展开成了 `def` 和 `fn`,前面例子中我们是分开使用的:
133 |
134 | ```clj
135 | ; 用 defn 这个 Macro 创建一个具名函数
136 | (defn greet [username]
137 | (str "Hello " username))
138 |
139 | ; defn 这个 Macro 的定义(极度简化版本)
140 | (defmacro defn [name args body]
141 | `(def ~name (fn ~args ~body)))
142 | ```
143 |
144 | __应用开发者极少需要为他们自己创建 Macros__, 但这项功能对于类库开发者来说是不可或缺的,
145 | 通过 Macro 他们可以为应用开发者提供语言本身最大的灵活性.
146 |
147 | #### 简单的替换
148 |
149 | 有几个 [Macro 字符](http://clojure.org/reader#The%20Reader--Macro%20characters)被用来进行简单的替换, 这使语言变得更简洁(不全是 Macro).
150 |
151 | ```clj
152 | ; 简单函数的一种简写
153 | ; #(...) => (fn [args] (...))
154 |
155 | #(* 3 %) ; => (fn [x] (* 3 x))
156 |
157 | #(* 3 (+ %1 %2)) ; => (fn [x y] (* 3 (+ x y)))
158 | ```
159 |
160 | ## 就这些语法了
161 |
162 | 要熟练使用 ClojureScript 仅仅了解语法是不够的.
163 | 不过了解了上面这些语法, 你应该可以比较轻松地查看各种例子了,
164 | 也可以推理数据是怎么被求值的, 怎么被到处传递的.
165 |
166 | ```clj
167 | ; 在 JavaScript Console 中打印
168 | (js/console.log "Hello World!")
169 |
170 | ; 创建局部的绑定(常量)
171 | (let [a (+ 1 2)
172 | b (* 2 3)]
173 | (js/console.log "The value of a is" a)
174 | (js/console.log "The value of b is" b))
175 |
176 | ; 创建数字的序列
177 | (range 4) ; => (0 1 2 3)
178 |
179 | ; 生成前 4 个自然数乘以 3 的结果
180 | (map #(* % 3) (range 4)) ;=> (0 3 6 9)
181 |
182 | ; 序列中的元素个数
183 | (count "Bob") ; => 3
184 | (count [4 5 2 3]) ; => 4
185 |
186 | ; 从列表中筛选出三个字母组成的名字
187 | (def names ["Bob" "David" "Sue"])
188 | (filter #(= (count %) 3) names) ; => ("Bob" "Sue")
189 | ```
190 |
191 | (不需要担心圆括号太多而迷失. 所有的现代文本编辑器都可以做到配对的括号的高亮, 甚至自动缩进代码来保证可读性, 就跟其他语言标准的做法一样.)
192 |
193 | ## HTML 模板语法中的 ClojureScript 对比 JSX
194 |
195 | 阅读 [Jumping from HTML to ClojureScript](https://github.com/shaunlebron/jumping-from-html-to-clojurescript) 来了解 ClojureScript 语法怎样解决 JavaScript 社区中 JSX 解决的冗长性(verbosity?)和灵活性的问题.
196 |
197 | [Jumping from HTML to ClojureScript]:https://github.com/shaunlebron/jumping-from-html-to-clojurescript
198 | [JSX]:https://facebook.github.io/react/docs/jsx-in-depth.html
199 |
200 | ## 完整的手册
201 |
202 | [ClojureScript API 手册]的语法章节可以找到所有可能的语法形式, 甚至还显示了源码怎样进行读取和解析.
203 |
204 | [syntax section]:https://github.com/cljsinfo/cljs-api-docs/blob/catalog/INDEX.md#syntax
205 | [ClojureScript API 手册]:http://cljs.github.io/api
206 |
207 | ## 实用资源
208 |
209 | 下面是我在学习 ClojureScript 时候的一些资源和步骤. (大部分介绍 Clojure 的资源对于 ClojureScript 也适用, 因为两者共享了很大的交集.)
210 |
211 | 1. Reading through the [ClojureScript Wiki](https://github.com/clojure/clojurescript/wiki)
212 | 1. Reading the book [ClojureScript Up and Running](http://synrc.com/publications/cat/Functional%20Languages/Clojure/Oreilly.ClojureScript.Up.and.Running.Oct.2012.pdf)
213 | 1. Reading the book [Clojure Programming](http://bit.ly/clojurebook)
214 | 1. Doing [ClojureScript Koans](http://clojurescriptkoans.com)
215 | 1. Reading [Clojure Style Guide](https://github.com/bbatsov/clojure-style-guide)
216 | 1. Reading [Clojure Programming By Example](http://en.wikibooks.org/wiki/Clojure_Programming/By_Example)
217 | 1. Reading [Clojure Functional Programming](http://clojure.org/functional_programming)
218 | 1. Thumbing through [Clojure Core API](http://clojure.github.io/clojure/clojure.core-api.html)
219 | 1. Reading [ClojureScript - Differences from Clojure - Host Interop](https://github.com/clojure/clojurescript/wiki/Differences-from-Clojure#wiki-host-interop) for accessing javascript properties like `(.-Infinity js/window)` and functions like `(.sqrt js/Math 25)`.
220 | 1. Reading [JavaScript to ClojureScript synonyms](http://kanaka.github.io/clojurescript/web/synonym.html)
221 | 1. Experimenting in `lein repl` for Clojure REPL.
222 | 1. Experimenting in for ClojureScript REPL with a browser context.
223 | 1. Reading docstrings of functions I encounter with `(doc )` in REPL.
224 | 1. [Miscellaneous ClojureScript things to know](https://github.com/shaunlebron/ClojureSheet#clojurescript-stuff)
225 |
--------------------------------------------------------------------------------
/img/calls.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaunlebron/ClojureScript-Syntax-in-15-minutes/7dec81134163c5c6a42a8f8b30762afa3c1347fe/img/calls.png
--------------------------------------------------------------------------------
/img/cljs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaunlebron/ClojureScript-Syntax-in-15-minutes/7dec81134163c5c6a42a8f8b30762afa3c1347fe/img/cljs.png
--------------------------------------------------------------------------------
/img/sublime-cljs-syntax.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/shaunlebron/ClojureScript-Syntax-in-15-minutes/7dec81134163c5c6a42a8f8b30762afa3c1347fe/img/sublime-cljs-syntax.png
--------------------------------------------------------------------------------