日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

(cljs/run-at (JSVM. :all) 细说函数)

發布時間:2023/12/19 javascript 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (cljs/run-at (JSVM. :all) 细说函数) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

?作為一門函數式編程語言,深入了解函數的定義和使用自然是十分重要的事情,下面我們一起來學習吧!

3種基礎定義方法

defn

定義語法

(defn name [params*]exprs*)

示例

(defn tap [ns x](println ns x)x)

fn

定義語法

(fn name? [params*]exprs*)

示例

(def tap(fn [ns x](println ns x)x))

其實defn是個macro,最終會展開為fn這種定義方式。因此后面的均以fn這種形式作說明。

Lambda表達式

定義語法

#(expr)

示例

(def tap#(do(println %1 %2)%2))

注意:

  • Lambda表達式的函數體只允許使用一個表達式,因此要通過special formdo來運行多個表達式;
  • 入參symbol為%1,%2,...%n,當有且只有一個入參時可以使用%來指向該入參。
  • Metadata——為函數附加元數據

    ?Symbol和集合均支持附加metadata,以便向編譯器提供額外信息(如類型提示等),而我們也可以通過metadata來標記源碼、訪問策略等信息。
    ?對于命名函數我們自然要賦予它Symbol,自然就可以附加元數據了。
    ?其中附加:private和defn-定義函數目的是一樣的,就是將函數的訪問控制設置為private(默認為public),但可惜的是cljs現在還不支持:private,所以還是要用名稱來區分訪問控制策略。
    示例:

    ;; 定義 (defn^{:doc "my sum function":test (fn [](assert (= 12 (mysum 10 1 1)))):custom/metadata "have nice time!"}mysum [& xs](apply + xs));; 獲取Var的metadata (meta #'mysum) ;;=> ;; {:name mysum ;; :custom/metadata "have nice time!" ;; :doc "my sum function" ;; :arglists ([& xs]) ;; :file "test" ;; :line 126 ;; :ns #<Namespace user> ;; :test #<user$fn_289 user$fn_289@20f443>}

    若只打算設置document string而已,那么可以簡寫為

    (defn mysum"my sum function"[& xs](apply + xs))

    雖然cljs只支持:doc

    根據入參數目實現函數重載(Multi-arity Functions)

    示例

    (fn tap([ns](tap ns nil))([ns x](println ns x))([ns x & more](println ns x more)))

    參數解構

    ?cljs為我們提供強大無比的入參解構能力,也就是通過聲明方式萃取入參

    基于位置的解構(Positional Destructuring)

    ;; 定義1 (def currency-of(fn [[amount currency]](println amount currency)amount));; 使用1 (currency-of [12 "US"]);; 定義2 (def currency-of(fn [[amount currency [region ratio]]](println amount currency region ratio)amount));; 使用2 (currency-of [12 "US" ["CHINA" 6.7]])

    鍵值對的解構(Map Destructuring)

    ;; 定義1,鍵類型為Keyword (def currency-of(fn [{currency :curr}](println currency)));; 使用1 (currency-of {:curr "US"});; 定義2,鍵類型為String (def currency-of(fn [{currency "curr"}](println currency)));; 使用2 (currency-of {"curr" "US"});; 定義3,鍵類型為Symbol (def currency-of(fn [{currency 'curr}](println currency)));; 使用3 (currency-of {'curr "US"});; 定義4,一次指定多個鍵 (def currency-of(fn [{:keys [currency amount]}](println currency amount)));; 使用4 (currency-of {:currency "US", :amount 12});; 定義5,一次指定多個鍵 (def currency-of(fn [{:strs [currency amount]}](println currency amount)));; 使用5 (currency-of {"currency" "US", "amount" 12});; 定義6,一次指定多個鍵 (def currency-of(fn [{:syms [currency amount]}](println currency amount)));; 使用6 (currency-of {'currency "US", 'amount 12});; 定義7,默認值 (def currency-of(fn [{:keys [currency amount] :or {currency "CHINA"}}](println currency amount)));; 使用7 (currency-of {:amount 100}) ;;=> 100CHINA;; 定義8,命名鍵值對 (def currency-of(fn [{:keys [currency amount] :as orig}](println (:currency orig))))(currency-of {'currency "US", 'amount 12}) ;;=> US

    可變入參(Variadic Functions)

    通過&定義可變入參,可變入參僅能作為最后一個入參來使用

    (def tap(fn [ns & more](println ns (first more))))(tap "user.core" "1" "2" "3") ;;=> user.core1

    命名入參(Named Parameters/Extra Arguments)

    ?通過組合可變入參和參數解構,我們可以得到命名入參

    (def tap(fn [& {:keys [ns msg] :or {msg "/nothing"}}](println ns msg)))(tap :ns "user.core" :msg "/ok") ;;=> user.core/ok (tap :ns "user.core") ;;=> user.core/nothing

    Multimethods

    ?Multi-Arity函數中我們可以通過入參數目來調用不同的函數實現,但有沒有一種如C#、Java那樣根據入參類型來調用不同的函數實現呢?clj/cljs為我們提供Multimethods這一殺技——不但可以根據類型調用不同的函數實現,還可以根據以下內容呢!

  • 類型
  • 屬性
  • 元數據
  • 入參間關系
  • ?想說"Talk is cheap, show me the code"嗎?在看代碼前,我們先看看到底Multimethods的組成吧
    1.dispatching function
    ?用于對函數入參作操作,如獲取類型、值、運算入參關系等,然后將返回值作為dispatching value,然后根據dispatching value調用具體的函數實現。

    ;; 定義dispatching function (defmulti name docstring? attr-map? dispatch-fn & options);; 其中options是鍵值對 ;; :default :default,指定默認dispatch value的值,默認為:default ;; :hierarchy {},指定使用的hierarchy object

    2.method
    ?具體函數實現

    ;; 定義和注冊新的函數到multimethod (defmethod multifn dispatch-val & fn-tail)

    3.hierarchy object
    ?存儲層級關系的對象,默認情況下所有相關的Macro和函數均采用全局hierarchy object,若要采用私有則需要通過(make-hierarchy)來創建。

    還是一頭霧水?上示例吧!
    示例1 —— 根據第二個入參的層級關系

    (defmulti area(fn [x y]y))(defmethod area ::a[x y](println "derive from ::a")) (defmethod area :default[x y](println "executed :default"))(area 1 `a) ;;=> executed :default (derive `a :a) (area 1 `a) ;;=>derive from ::a

    示例2 -- 根據第一個入參的值

    (defmulti area(fn [x y]x))(defmethod area 1[x y](println "x is 1")) (defmethod area :default[x y](println "executed :default"))(area 2 `a) ;;=> executed :default (area 1 :b) ;;=> x is 1

    示例3 -- 根據兩入參數值比較的大小

    (defmulti area(fn [x y](> x y)))(defmethod area true[x y](println "x > y")) (defmethod area :default[x y](println "executed :default"))(area 1 2) ;;=> executed :default (area 2 3) ;;=> x > y

    ?刪除method

    ;; 函數簽名 (remove-method multifn dispatch-val);; 示例 (remove-method area true)

    分發規則

    ?先對dispatching value和method的dispatching-value進行=的等于操作,若不匹配則對兩者進行isa?的層級關系判斷操作,就這樣遍歷所有注冊到該multimethod的method,得到一組符合的method。若這組method的元素個數有且僅有一個,則執行該method;若沒有則執行:default method,若還是沒有則拋異常。若這組method的元素個數大于1,且沒有人工設置優先級,則拋異常。
    ?通過prefer-method我們可以設置method的優先級

    (derive `a `b) (derive `c `a)(defmulti test(fn [x](x)))(defmethod test `a[x](println "`a"))(defmethod test `b[x](println "`b"));; (test `c) 這里就不會出現多個匹配的method (prefer-method `a `b) (test `c) ;;=> `a

    層級關系

    ?層級關系相關的函數如下:

    ;; 判斷層級關系 (isa? h? child parent) ;; 構造層級關系 (derive h? child parent) ;; 解除層級關系 (underive h? child parent) ;; 構造局部hierarchy object (make-hierarchy)

    上述函數當省略h?時,則操作的層級關系存儲在全局的hierarchy object中。
    注意:層級關系存儲在全局的hierarchy object中時,Symbole、Keyword均要包含命名空間部分(即使這個命名空間并不存在),否則會拒絕。

    (ns cljs.user);; Symbole, `b會展開為cljs.user/b (derive 'dummy/a `b) ;; Keyword, ::a會展開為cljs.user/:a (derive ::a ::b)

    另外還有parent、ancestors和descendants

    (derive `c `p) (derive `p `pp);; 獲取父層級 (parent `c) ;;=> `p ;; 獲取祖先 (ancestors `c) ;;=> #{`p `pp} ;; 獲取子孫 (descendants `pp) ;;=> #{`p `c}

    局部層級關系

    ?通過(make-hierarchy)可以創建一個用于實現局部層級關系的hierarchy object

    (def h (make-hierarchy)) (def h (derive h 'a 'b)) (def h (derive h :a :b))(isa? h 'a 'b) (isa? h :a :b)

    注意:局部層級關系中的Symbol和Keyword是可以包含也可以不包含命名空間部分的哦!

    Condition Map

    ?對于動態類型語言而言,當入參不符合函數定義所期待時,是將入參格式化為符合期待值,還是直接報錯呢?我想這是每個JS的工程師必定面對過的問題。面對這個問題我們應該分階段分模塊來處理。

  • 開發階段,對于內核模塊,讓問題盡早暴露;
  • 生產階段,對于與用戶交互的模塊,應格式化輸入,并在后臺記錄跟蹤問題。
    ?而clj/cljs函數中的condition map就是為我們在開發階段提供對函數入參、函數返回值合法性的斷言能力,讓我們盡早發現問題。
  • (fn name [params*] condition-map? exprs*) (fn name ([params*] condition-map? exprs*)+); condition-map? => {:pre [pre-exprs*] ; :post [post-exprs*]} ; pre-exprs 就是作為一組對入參的斷言 ; post-exprs 就是作為一組對返回值的斷言

    示例

    (def mysum(fn [x y]{:pre [(pos? x) (neg? y)]:post [(not (neg? %))]}(+ x y)))(mysum 1 1) ;; AssertionError Assert failed: (neg? y) user/mysum (mysum -1 1) ;; AssertionError Assert failed: (pos? x) user/mysum (mysum 1 -2) ;; AssertionError Assert failed: not (neg? %)) user/mysum

    ?在pre-exprs中我們可以直接指向函數的入參,在post-exprs中則通過%來指向函數的返回值。
    ?雖然增加函數執行的前提條件,而且可以針對函數的值、關系、元數據等進行合法性驗證,但依舊需要在運行時才能觸發驗證(這些不是運行時才觸發還能什么時候能觸發呢?)。對動態類型語言天然編譯期數據類型驗證,我們可以通過core.typed這個項目去增強哦!

    總結

    ?現在我們可以安心把玩函數了,oh yeah!
    尊重原創,轉載請注明來自:http://www.cnblogs.com/fsjohnhuang/p/7137597.html ^_^肥仔John

    總結

    以上是生活随笔為你收集整理的(cljs/run-at (JSVM. :all) 细说函数)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。