(cljs/run-at (JSVM. :browser) "命名空间就这么简单")
前言
一个cljs文件定义一个命名空间,通过命名空间可以有效组织代码,这是构建大型系统必备的基础设施。本篇我们就深入理解cljs中的命名空间吧!
好习惯从"头"开始
每个cljs文件首行非注释的内容必定如下
(ns my-project.core)
而当前的cljs文件路径为${project_dir}/src/my_project/core.cljs
,很明显命名空间与源码文件路径是一一对应的,对应规则是-
对应_
,.
对应/
咯~
引入其他命名空间
要使用其他命名空间下的成员,那么必须先将其引入到当前命名空间才可以。但注意的是,默认情况下会自动引入cljs.core
这个命名空间,而且会将其成员注入到当前命名空间中。因此(ns my-project.core)
最后会编译为等价于以下语句
;; 注意:cljs中并不支持:all这种引入,因此这面语句仅仅用于表达注入所有成员而已
(ns my-project.core
(:require [cljs.core :all]))
所以我们可以直接调用reduce
而不是cljs.core/reduce
。
我们没可能只调用cljs.core
的成员吧,那到底如何引入其他命名空间呢?下面我们一一道来!
通过: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.为命名空间起别名
(ns my-project.core
(:require [clojure.data :as data]))
;; 使用时需要指定成员所属的命名空间的别名
(data/diff 1 2)
4.重命名注入的成员
(ns my-project.core
(:require [clojure.data :refer [diff] :rename {diff difference}]))
;; 使用时仅能使用别名
(difference 1 2)
;; (diff 1 2) 这里使用原名会报错
5.引入同命名空间的marco
;; 引入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/fsjohnhuang/p/7096800.html _肥仔John
(cljs/run-at (JSVM. :browser) "命名空间就这么简单")的更多相关文章
- (cljs/run-at (JSVM. :browser) "搭建刚好可用的开发环境!")
前言 书接上一回,在了解cljs基本语法后并在clojurescript.net的奇特错误提示后,我们必须痛定思痛地搭建一个本地的开发环境,以便后续深入地学习cljs. 现有的构建工具 由于浏览器 ...
- (cljs/run-at (->JSVM :browser) "语言基础")
前言 两年多前知道cljs的存在时十分兴奋,但因为工作中根本用不上,国内也没有专门的职位于是搁置了对其的探索.而近一两年来又刮起了函数式编程的风潮,恰逢有幸主理新项目的前端架构,于是引入Ramda. ...
- (cljs/run-at (JSVM. :browser) "简单类型可不简单啊~")
前言 每逢学习一个新的语言时总要先了解这门语言支持的数据类型,因为数据类型决定这门语言所针对的问题域,像Bash那样内置只支持字符串的脚步明显就是用于文本处理啦.而数据类型又分为标量类型(Scala ...
- [browser location和history] 简单实现了个路由[转载]
今天看了1下前面写的,好像缺乏交流性,周末再来弄吧 -0- 今天看了browser 的 location 和 history location属性 // //location.hash 性是一个可读可 ...
- Previous operation has not finished; run 'cleanup' if it was interrupted最简单有效的解决方法
今天提交代码报错,看了看提示的错误,百度了一下,发现操作都比较繁琐,所以自己重新给一个最简单有效的. 有的要下载sqlite3.exe,借助它清空本地.svn\wc.db数据库文件里面的operati ...
- 微软官方网站线上兼容测试平台-Browser screenshots
前端开发时最不想做的就是在不同浏览器.平台和分辨率测试网页显示效果,通常这会浮现许多问题,尤其浏览器版本就可能让显示成效完全不同,也只好尽力维持让每一种设备都能正常浏览网页.修改到完全没有问题必须投入 ...
- TypeScript学习笔记(七) - 命名空间
本篇将介绍TypeScript的命名空间,并简单说明一下与模块的区别. 在之前的例子里,有如下一段代码,通过修改这段代码来演示命名空间的用法. interface Animal { name: str ...
- XAML的命名空间
原文:XAML的命名空间 一个最简单的XAML例子 <Window x:Class="WpfApplication1.MainWindow" xmlns="ht ...
- Go routine 编排框架:oklog/run 包
目录 Go routine 编排框架:oklog/run 包 问题引入 oklog/run 包介绍 使用例子 参考资料 Go routine 编排框架:oklog/run 包 问题引入 oklog/r ...
随机推荐
- 使用JS开发桌面端应用程序NW.js-1-Menu菜单的使用小记
前言 本文主要内容为nw.js官方文档中没有提到,而在实际入手开发过程中才碰到的问题以及经验的汇总. 详情请查看官方文档:http://docs.nwjs.io/en/latest/Reference ...
- redis集群添加删除节点
Redis3.0集群添加节点 1:首先把需要添加的节点启动 cd /usr/local/cluster/ mkdir 7006 cp /usr/local/cluster/redis.conf /u ...
- [刷题]算法竞赛入门经典 3-7/UVa1368 3-8/UVa202 3-9/UVa10340
书上具体所有题目:http://pan.baidu.com/s/1hssH0KO 都是<算法竞赛入门经典(第二版)>的题目,标题上没写(第二版) 题目:算法竞赛入门经典 3-7/UVa13 ...
- SSO单点登录的研究
一.单点登录的概述 单点登录(Single Sign On),简称为 SSO,SSO的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统. 用以解决同一公司不同子产 ...
- win10下使用nodejs安装及webstorm创建express项目的指导
title: win10下使用nodejs安装 win10下使用nodejs安装及webstorm创建express项目的指导 windows下nvm的安装 熟悉linux下nodejs开发的朋友应该 ...
- Ehcache 整合Spring 使用页面、对象缓存(1)
转自:http://www.cnblogs.com/hoojo/archive/2012/07/12/2587556.html Ehcache在很多项目中都出现过,用法也比较简单.一般的加些配置就可以 ...
- List在执行remove方法不能删除指定的对象
我们根据List中的源码分析, remove方法的原理: public boolean remove(Object o){ if(o ==null) { for(inti ...
- js实现谷歌坐标转百度坐标
js实现谷歌坐标转百度坐标 谷歌坐标转百度坐标 实现算法如下(以js为例,其他语言调整就行): //$lat 维度:$lng 经度 function GCJTobaidu($lat, $lng){ ...
- php处理表单中的复选框问题以及js实现全选
做的一个项目中遇到了全选和取消全选的问题,这是一个很普遍的功能,,虽然我们经常用到,但是真正做起来却发现行不通,在网上找了些,大部分都是ie,但是谷歌内核浏览器不能正常实现,所以经过小小的调整,今天就 ...
- php curl 的几个实例
使用PHP的cURL库可以简单和有效地去抓网页.你只需要运行一个脚本,然后分析一下你所抓取的网页,然后就可以以程序的方式得到你想要的数据了.无论是你想从从一个链接上取部分数据,或是取一个XML文件并把 ...