Skip to content

Latest commit

 

History

History
473 lines (370 loc) · 13.8 KB

cljs-for-impatient.md

File metadata and controls

473 lines (370 loc) · 13.8 KB

title: Insert Title here author: name: Джон, просто Джон github: sudodoki twitter: sudodoki theme: sudodoki/reveal-cleaver-theme-bright output: index.html

--

<style> @font-face { font-family: "WebUpheavalPro"; src: url("fonts/Upheaval/UpheavalPro.otf") format("opentype"), url("fonts/Upheaval/UpheavalPro.ttf") format("truetype"); } .reveal code { // font-family: "Joystix"; font-size: 45px; line-height: 50px; } .reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6 { font-family: "Upheaval Pro", "WebUpheavalPro", "Source Sans Pro", Helvetica, sans-serif;; } .reveal .roll { vertical-align: middle; } .reveal .truncate code, .reveal .truncate pre { display: inline-block; width: auto; } </style>

Джон для khjs #1

--

Кто такой Джон Галт?

  • Тимлид в R⚡️R
  • Соорганизатор KyivJS
  • Котан в kottans.org

--

Почему я делаю этот доклад?

  • Меня пригласили
  • Я в очередной раз интересуюсь ClojureScript
  • Слежу за языком и вам советую

--

Команда "Enterprise"

Your Generic language Java Haskell Clojure JS ––
В данной аналогии JS = двигатель корабля

--

ClojureScript

  • "Младший брат" Clojure
  • Clojure использует JVM / CLR / JS как хост
  • Минус вещи для работы с многопоточностью

--

Простота vs Легкость

Рич Хикки топит за простоту, а кложура делает её легкой

--

Также в номере

  • Воспитание функционального мышления
  • Фронтенд на cljs = пуля в борьбе с JS снобами
  • Иммутабельность по дефолту
  • Практичность и разумные компромиссы
  • Встраиваемость
  • Комьюнити
  • Эксперименты
  • Кладезь для идей

--

Синтаксис

--

Тут у меня if и выполнится эта ветка, но скобочек нет, значит выполнится только первое выражение из неё, а эти выражения тогда что?

--

/*
<Str>
  <p>hello</p>
  <p>world</p>
</Str>
*/

--

React.createElement(
  Str, null,
    React.createElement(
      'p', null, 'hello'
    ),
    React.createElement(
      'p', null, 'world'
    ))

--

;function      arg2   arg3
;↓              ↓      ↓
(+      1       2      3)
(str "hello" "world")
;
;      arg1

--

Вложенность

(def r 5)
(defn square [x] (* x x))

(* (.-PI js/Math) (square r))

--

(map #(* (.-PI js/Math)
         (square %))
      [1 2 3])

(map (fn [radius]
        (* (.-PI js/Math)
           (square radius)))
     [1 2 3])

--

Список

(1 2 3)
Вызов функции
(fn arg1 arg2)

--

Постойте…

--

Код = Данные

--

Система макросов

для расширения языка

--

Простые типы

  • Числа 5, 12.15, 3/10
  • Ключевые слова :when, :id, :foobar
  • Символы my-fn, my-var, +, /
  • Строки "Hello", "World"
  • Буквы \newline, \a

--

Основные коллекции

  • Списки (list 1 2 3), '(1 2 3)
  • Векторы (vector 1 2 3), [1 2 3]
  • Хеш-таблицы (hash-map :a 1 :b 2), {:a 1 :b 2}
  • Множества (set '(1 2 3)), #{1 2 3}

--

Зачастую то, что работает на одном типе коллекции – будет работать и на других

--

Иммутабельность

--

; Ignoring other *JS
(def cityjs
  {:kharkiv ["KharkivJS"]})

--

(assoc cityjs
  :kharkiv
  (conj
    (:kharkiv cityjs)
    "KhJS"))
; => {:kharkiv
;     ["KharkivJS" "KhJS"]}

--

(update-in cityjs
  [:kharkiv]
  #(conj % "KhJS"))
; => {:kharkiv 
;     ["KharkivJS" "KhJS"]}

--

Преимущества

  • производительность структур и их сравнения
  • общие структурные элементы

--

Функции и ФП

  • функции как объекты первого класса
  • композиция, частичное применение
  • поддержка нескольких арностей
  • диспатчинг по функции

--

(defn greet
    ([salute]
        (greet salute "world"))
    ([salute who]
        (println salute who)))
; cljs.user=> (greet "hey")
; hey world
; nil

--

(defmulti refactor :framework)
; same as
; (defmulti refactor
;           #(% :framework))

--

(defmethod refactor :angular
  [{name :name}]
  (println "Rewrite"
           name
           "in react"))  

--

(refactor {
  :framework :angular
  :name "My TODO App"})
; Rewrite My TODO App in react
; nil

--

In -| transform |-> Out

Вообще, в итоге построение программы сводится к тому, чтобы придумать, какую структуру данных вы получаете на входе, какую вы хотите получить на выходе и написать трансформацию на основании функций, что превратит первое во второе
--

Практичность

  • Вещи, которые считаются плохими, делаются явными (мутации и !, …)
  • Доступ к хост платформе (.random js/Math)
  • При принятии решения "умное/чистое vs практичное" – выбирают практичное

--

Дайте мне точку входа и я весь переколбашу проект*

* – предполагаем, что у вас Leiningen

project.clj

(defproject color-clock "0.1.0-SNAPSHOT"
  :description "FIXME: write this!"
  :dependencies [
    [org.clojure/clojure "1.8.0"]
    [org.clojure/clojurescript "1.9.456"]
    [reagent "0.6.0"]]
  :jvm-opts ^:replace ["-Xmx1g" "-server"]
  :plugins [[lein-npm "0.6.1"]]
  :npm {:dependencies [[source-map-support "0.4.0"]]}
  :source-paths ["src" "target/classes"]
  :clean-targets ["out" "release"]
  :target-path "target")

--

Как такой получить?

  • написать руками
  • сделать lein new %template% project-name

--

%template%

--

Работа с DOM

--

(defn clock-page []
  (let [cur-time (r/atom (get-current-time))]
    (add-watch cur-time :seconds println)
    (fn []
      (js/setTimeout
        #(reset! сur-time (get-current-time)) 1000)
      [:div {:class "holder" 
             :style {"backgroundColor"
                     (time-to-rgb @current-time)}} 
        [:h1 (interpose ":" @current-time)]])))
(r/render [clock-page]
  (.getElementById js/document "app"))

--

let он и в Африке let

(let [somevar "somevalue"]
  (use-local-binding somevar))

--

Atom

(def answer (atom 42))
(println (deref answer))
(println @answer) ; => 42
(swap! answer #(* 2 %)) ; => 84
(compare-and-set! answer 42 13)
; => false
(reset! answer 42) ; => 42

using reagent/atom to get automagical rerendering

Markup

[:div
  {:class "holder" 
   :style {
     "backgroundColor"
      (time->rgb @cur-time)}} 
  [:h1 (interpose ":" @cur-time)
]]

Хотите просто хтмл – enlive

(ns color-clock.core
  (:require
    [reagent.core :as r]
    [goog.string :as str]))

Имя неймспейса ↔ путь к файлу
Поэтому, в примере выше src/color_clock/core.cljs

--

(defn clock-page []
  (let [cur-time (r/atom (get-current-time))]
    (add-watch cur-time :seconds println)
    (fn []
      (js/setTimeout
        #(reset! сur-time (get-current-time)) 1000)
      [:div {:class "holder" 
             :style {"backgroundColor"
                     (time-to-rgb @current-time)}} 
        [:h1 (interpose ":" @current-time)]])))
(r/render [clock-page]
  (.getElementById js/document "app"))

--

За кадром

--



--

Continue? Y/N