一个cljs文件定义一个命名空间,经过命名空间能够有效组织代码,这是构建大型系统必备的基础设施。本篇咱们就深刻理解cljs中的命名空间吧!html
每一个cljs文件首行非注释的内容一定以下git
(ns my-project.core)
而当前的cljs文件路径为${project_dir}/src/my_project/core.cljs
,很明显命名空间与源码文件路径是一一对应的,对应规则是-
对应_
,.
对应/
咯~github
要使用其余命名空间下的成员,那么必须先将其引入到当前命名空间才能够。但注意的是,默认状况下会自动引入cljs.core
这个命名空间,并且会将其成员注入到当前命名空间中。所以(ns my-project.core)
最后会编译为等价于如下语句app
;; 注意:cljs中并不支持:all这种引入,所以这面语句仅仅用于表达注入全部成员而已 (ns my-project.core (:require [cljs.core :all]))
因此咱们能够直接调用reduce
而不是cljs.core/reduce
。
咱们没可能只调用cljs.core
的成员吧,那到底如何引入其余命名空间呢?下面咱们一一道来!ide
:require
1.直接引入函数
(ns my-project.core (:require clojure.data)) ;; 使用时须要指定成员所属的命名空间 (clojure.data/diff 1 2)
2.注入成员到当前命名空间优化
; 将clojure.data/diff和clojure.data/Diff两个成员注入到当前命名空间 (ns my-project.core (:require [clojure.data :refer [diff Diff]])) ;; 直接使用便可 (diff 1 2) (defrecord MyRecord [x] Diff (diff-similar [a b] (= (:x a) (:x b))))
3.为命名空间起别名ui
(ns my-project.core (:require [clojure.data :as data])) ;; 使用时须要指定成员所属的命名空间的别名 (data/diff 1 2)
4.重命名注入的成员code
(ns my-project.core (:require [clojure.data :refer [diff] :rename {diff difference}])) ;; 使用时仅能使用别名 (difference 1 2) ;; (diff 1 2) 这里使用原名会报错
5.引入同命名空间的marcoorm
;; 引入helper.core下的全部macro (ns my-project.core (:require [helper.core :as h :include-macros true])) (h/i-am-macro1) (h/i-am-macro2) (h/i-am-function) ;; 引入helper.core下指定的macro (ns my-project.core (:require [helper.core :as h :refer-macros [i-am-macro1]])) (h/i-am-macro1) ;; 能够不用指定marco所属的命名空间哦! (i-am-macro1) (h/i-am-function)
helper/core.cljs文件
(ns helper.core) (defn i-am-function [] (println "i-am-function"))
helper/core.clj文件
(ns helper.core) (defmacro i-am-macro1 [] '(println "i-am-macro1")) (defmacro i-am-macro2 [] '(println "i-am-macro2"))
因为macro是在编译期展开为列表,而后在运行时解析列表,而JS做为脚本语言根本就没有全部编译期,所以须要将macro写在独立的clj文件中,而后在cljs编译为js时展开。因此当咱们在同一个命名空间定义普通成员和macro时,只需命名两个名称同样当扩展名不一样的cljs和clj便可。
6.一次引入多个命名空间
(ns my-project.core (:require [clojure.data :as data] [cljs.test :refer [is]] clojure.string))
:use
:use
其实至关于:require
加上:refer
那样,通常建议用后者代替。
(ns my-project.core (:use clojure.data :only [diff Diff])) (diff 1 2)
(ns my-project.core (:use clojure.data :only [diff] :rename {diff difference})) (difference 1 2)
:require-macros
引入macro其实经过:require
中引入macro已经间接接触到:require-macros
了,由于它实际上会解析成:require-macros
来使用的!
1.为命名空间起别名
(ns my-project.core (:require-macros helper.core :as h)) (h/i-am-macro1)
2.注入macro到当前命名空间
(ns my-project.core (:require-macros helper.core :refer [i-am-macro1])) (i-am-macro1)
3.注入macro到当前命名空间,并起别名
(ns my-project.core (:require-macros helper.core :refer [i-am-macro1] :rename {i-am-macro1 m1})) (m1)
:use-macros
引入macro :use-macros
其实至关于:require-macros
加上:refer
那样,通常建议用后者代替。
(ns my-project.core (:use-macros helper.core :only [i-am-macro1])) (i-am-macro1)
(ns my-project.core (:use-macros helper.core :only [i-am-macro1] :rename {i-am-macro1 m1})) (m1)
:import
引入Google Closure中的类型和枚举类 注意:import
只能用于引入Google Closure中的类型,而其余类型、成员等等所有用:require
引入就行了。
(ns my-project.core (:import goog.math.Long [goog.math Vec2 Vec3])) (Long. 4 6) (Vec2. 1 2) (Vec3. 1 2 3)
:refer-clojure
重置clojure内置的symbol 咱们知道默认状况下会自动注入cljs.core
的成员到当前命名空间中,所以咱们能够直接使用+
、-
等函数。若是此时咱们自定义一个名为+
的函数,那么就会让下次要使用加法函数时则须要写成cljs.core/+
,这样总感受不太好。那么咱们能够借助:refer-clojure
来重置这些内置symbol了。
(ns my-project.core (:refer-clojure :rename {+ math_add})) (defn + [& more] (apply math_add more))
另外还能够直接丢弃(不用就不要注入够环保的啊!)
(ns my-project.core (:refer-clojure :exclude [+])) (+) ;; 报错了!
clojure.*
将自动转为cljs.*
cljs的好处就是能够直接使用与宿主环境无关的clj代码,因此咱们能够直接引入clojure.string
、clojure.data
等命名空间,但有时难免会记错或新版本提供了更贴地气(针对特定宿主优化过)的版本,那是否是就要改为cljs的版本呢?放心cljs编译器会自动帮你搞定!
(ns testme.core (:require [clojure.test])) ;; 会自动转换为 (ns testme.core (:require [cljs.test :as clojure.test]))
require
用在REPL中就行了 在REPL中咱们会使用如require
、use
、require-macros
、import
等macro来引入命名空间。请紧记,这些确实仅仅用于REPL中而已。并且当咱们修改源码后,须要经过(require 命名空间 :reload)
来重置并从新加载这个命名空间,不带:reload
的话新修改的功能将不会生效哦!
注意:require
后的命名空间须要以单引号为起始,从而避免将其从symbol解析为var而后取其值。如
(require 'clojure.data) (require '[clojure.set :as s])
根据clojure-style-guide描述优先级别以下::require :as
> :require :refer
:require
> :use
而声明顺序以下::refer-clojure
>:require
>:import
如今咱们能够安心开始书写第一个自定义命名空间了,可是不是仍是有点不安稳的感受呢?是否是上面提到Special Form
、Symbol
、Var
等一头雾水呢?下一篇(cljs/run-at (JSVM. :browser) "简单类型可不简单啊~")
尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohn... ^_^肥仔John