| CARVIEW |
ClojureScript Cheatsheet
Basics
Numbers
| Literals | 73.14-1.2e30x0000ff |
| Arithmetic | +-*/quotremmodincdecmaxmin |
| Compare | ===not=<><=>=compare |
| Cast | int |
| Test | zero?pos?neg?even?odd?number?integer? |
| Random | randrand-int |
" " Strings
| Create | "abc"strname |
| Use | (.-length my-str)countgetsubs(clojure.string/)joinescapesplitsplit-linesreplacereplace-firstreverse |
| Regex | #"pattern"re-findre-seqre-matchesre-pattern(clojure.string/)replacereplace-first |
| Letters | (clojure.string/)capitalizelower-caseupper-case |
| Trim | (clojure.string/)trimtrim-newlinetrimltrimr |
| Test | string?(clojure.string/)blank?starts-with?ends-with?includes? |
Atoms / State
| Create | atom |
| Get Value | @my-atom → (deref my-atom) |
| Set Value | swap!reset!compare-and-set! |
| Watch | add-watchremove-watch |
| Validators | set-validator!get-validator |
JavaScript Interop
| Create Object | #js {}js-obj |
| Create Array | #js []arraymake-arrayaclone |
| Get Property | (.-innerHTML el) |
| Set Property | (set! (.-innerHTML el) "Hi!") |
| Delete Property | js-delete |
| Convert Between | clj->jsjs->clj |
| Type Tests | array?fn?number?object?string? |
| Exceptions | trycatchfinallythrow |
| External Library | (js/alert "Hello world!") (js/console.log my-obj) (.html (js/jQuery "#myDiv") "Hi!") |
Basics
Numbers
| Literals | 73.14-1.2e30x0000ff |
| Arithmetic | +-*/quotremmodincdecmaxmin |
| Compare | ===not=<><=>=compare |
| Cast | int |
| Test | zero?pos?neg?even?odd?number?integer? |
| Random | randrand-int |
JavaScript Interop
| Create Object | #js {}js-obj |
| Create Array | #js []arraymake-arrayaclone |
| Get Property | (.-innerHTML el) |
| Set Property | (set! (.-innerHTML el) "Hi!") |
| Delete Property | js-delete |
| Convert Between | clj->jsjs->clj |
| Type Tests | array?fn?number?object?string? |
| Exceptions | trycatchfinallythrow |
| External Library | (js/alert "Hello world!") (js/console.log my-obj) (.html (js/jQuery "#myDiv") "Hi!") |
#( ) Functions
| Create | #(...) → (fn [args] (...)) fndefndefn-identityconstantlycompcomplementpartialjuxtmemoizefnilevery-predsome-fn |
| Call | apply->->>as->cond->cond->>some->some->> |
| Test | fn?ifn? |
" " Strings
| Create | "abc"strname |
| Use | (.-length my-str)countgetsubs(clojure.string/)joinescapesplitsplit-linesreplacereplace-firstreverse |
| Regex | #"pattern"re-findre-seqre-matchesre-pattern(clojure.string/)replacereplace-first |
| Letters | (clojure.string/)capitalizelower-caseupper-case |
| Trim | (clojure.string/)trimtrim-newlinetrimltrimr |
| Test | string?(clojure.string/)blank?starts-with?ends-with?includes? |
Atoms / State
| Create | atom |
| Get Value | @my-atom → (deref my-atom) |
| Set Value | swap!reset!compare-and-set! |
| Watch | add-watchremove-watch |
| Validators | set-validator!get-validator |
Collections
[ ] Vectors
| Create | []vectorvec |
| Examine | (my-vec idx) → (nth my-vec idx) getpeek |
| 'Change' | assocpopsubvecreplaceconjrseq |
| Loop | mapvfiltervreduce-kv |
#{ } Sets
| Create | #{}sethash-setsorted-setsorted-set-by |
| Examine | (my-set itm) → (get my-set itm) contains? |
| 'Change' | conjdisj |
| Set Ops | (clojure.set/)uniondifferenceintersectionselect |
| Test | (clojure.set/)subset?superset? |
{ } Maps
| Create | {:key1 "a" :key2 "b"} hash-maparray-mapzipmapsorted-mapsorted-map-byfrequenciesgroup-by |
| Examine | (:key my-map) → (get my-map :key) get-incontains?findkeysvals |
| 'Change' | assocassoc-indissocmergemerge-withselect-keysupdate-in |
| Entry | keyval |
| Sorted Maps | rseqsubseqrsubseq |
Collections
| General | countemptynot-emptyintoconj |
| Content Tests | distinct?empty?every?not-every?somenot-any? |
| Capabilities | sequential?associative?sorted?counted?reversible? |
| Type Tests | coll?list?vector?set?map?seq? |
{ } Maps
| Create | {:key1 "a" :key2 "b"} hash-maparray-mapzipmapsorted-mapsorted-map-byfrequenciesgroup-by |
| Examine | (:key my-map) → (get my-map :key) get-incontains?findkeysvals |
| 'Change' | assocassoc-indissocmergemerge-withselect-keysupdate-in |
| Entry | keyval |
| Sorted Maps | rseqsubseqrsubseq |
[ ] Vectors
| Create | []vectorvec |
| Examine | (my-vec idx) → (nth my-vec idx) getpeek |
| 'Change' | assocpopsubvecreplaceconjrseq |
| Loop | mapvfiltervreduce-kv |
#{ } Sets
| Create | #{}sethash-setsorted-setsorted-set-by |
| Examine | (my-set itm) → (get my-set itm) contains? |
| 'Change' | conjdisj |
| Set Ops | (clojure.set/)uniondifferenceintersectionselect |
| Test | (clojure.set/)subset?superset? |
Sequences
Seq in, Seq out
Seq in, Seq out
Misc
Everything in ClojureScript is immutable by default, meaning that the value of a symbol cannot be changed after it is defined.
In conditional statements, everything evaluates to true except for false and nil.
This is much simpler than JavaScript, which has complex rules for truthiness.
| Name | Code | Boolean Value |
|---|---|---|
| Empty string | "" | true |
| Zero | 0 | true |
| Not a number | js/NaN | true |
| Empty vector | [] | true |
| Empty array | (array) | true |
| False | false | false |
| Nil | nil | false |
All ClojureScript Numbers are IEEE 754 Double Precision floating point. The same as JavaScript.
Atoms provide a way to manage state in a ClojureScript program.
Unlike JavaScript, everything in ClojureScript is immutable by default. This means that you cannot change the value of something after it has been defined.
Atoms allow for mutability and distinguish between setting and reading a value, which makes state easier to reason about.
Watcher functions execute when a value changes, providing a powerful UI pattern when your value maps to interface state.
ClojureScript Functions are JavaScript Functions and can be called and used in all the ways that JavaScript Functions can.
The core library provides many useful higher-order functions and there is a convenient shorthand for creating anonymous functions.
The #() function shorthand is a convenient way to write a small function definition and is often used to pass closures from one scope to another.
#() forms cannot be nested and it is idiomatic to keep them short.
| Shorthand | Expands To |
|---|---|
| #(str "Hello " %) | (fn [n] (str "Hello " n)) |
| #(my-fn %1 %2 %3) | (fn [a b c] (my-fn a b c)) |
| #(* % (apply + %&)) | (fn [x & the-rest] (* x (apply + the-rest))) |
ClojureScript Strings are JavaScript Strings and have all of the native methods and properties that a JavaScript String has.
ClojureScript Strings must be defined using double quotes.
The clojure.string namespace provides many useful functions for dealing with strings.
ClojureScript provides four collection types: lists, vectors, sets, and maps. Each of these data types has unique strengths and are used heavily in most programs.
All collections are immutable and persistent, which means they preserve the previous version(s) of themselves when they are modified. Creating a "changed" version of any collection is an efficient operation.
Collections can be represented literally:
| Collection | Literal Form |
|---|---|
| List | () |
| Vector | [] |
| Set | #{} |
| Map | {} |
Lists are a sequence of values, similar to a vector.
Most literal lists represent a function call.
(a b c) is a list of three things, and it also means "call the function a with two arguments: b and c"
Vectors are collections of values that are indexed by sequential integers.
Though similar, a JavaScript Array is not the same thing as a ClojureScript vector. ie: (.indexOf my-vec) will not work on a vector.
A vector can be used as a function to access its elements.
Sets are collections of unique values, just like in mathematics.
A set can be used as a function to access its elements.
A map is a collection that maps keys to values. Accessing a value in a map using a key is very fast.
In JavaScript, Objects are commonly used as a de facto map using strings as keys. A key in a ClojureScript map can be any value, although keywords are commonly used.
Keywords can be used as a function to get a value from a map. They are commonly used as map keys for this reason.
Many core algorithms are defined in terms of sequences. A sequence is an interface to a list structure that allows for algorithms to be written in a generic way.
Every sequence is a collection, and every collection can be converted into a sequence using the seq function. In fact, this is what happens internally when a collection is passed to a sequence function.
Most of the sequence functions are lazy, which means that they consume their elements incrementally as needed. For example, it is possible to have an infinite sequence.
You can force a sequence to evaluate all its elements with the doseq function. This is useful when you want to see the results of a side-effecting function over an entire sequence.