- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我刚刚开始在 node-js 端使用 clojurescript。我用它来构建将在节点上运行的命令行工具。现在我已经设置了我的概念验证并且或多或少地做了我想做的事情,是时候更好地组织代码了。
在 JS 上,当我需要类似于已配置的 http 客户端的东西时,我通常会导出一个函数,该函数接受基本参数并返回一个对象,该对象具有绑定(bind)到该参数的方法(通常使用显示模块模式)。类似于在 OOP 上创建新实例的东西。这是我如何在 JS 上执行此操作的一个小示例:
const request = require('request')
module.exports = (user, pass, baseUrl) => {
const client = request.defaults({baseUrl, auth: {user, pass}})
const getSomething = (name) => client.get('resources/' + name)
const createSomething = (name, options) => client.post('resources', {...})
return { getSomething, createSomething }
}
但是在 clojurescript 上我找不到合适的方法。所有定义都是在编译时计算的顶级声明,并且制作上述结构需要使用客户端参数声明我的所有函数,然后部分应用它们并在逻辑主体上使用它们。这可能是这样的:
(ns some-client [:require ["request" :as request]])
(defn get-something [client, name]
(.get client (str "resources/" name)))
(defn create-something [client, name, options]
(.post client (str "resources") {:name name :data: options}))
(defn make-client [usr, pass, baseUrl]
(let [client (.defaults request {:auth {:user usr :pass pass} :baseUrl baseUrl})]
{:get-something (partial get-something client)
:create-something (partial create-something client)}))
这可能看起来还不错,但是一旦您需要在另一个所有功能都需要此类客户端的地方使用它,事情就会开始变得困惑。您将需要在所有功能上接受客户端,如果其他命名空间只是您需要在另一个地方使用的功能集合,您将被迫遵循返回客户端创建者的相同模式,接受客户端您依赖并确保将其传递给可能需要它的每个功能。我可以变得像这样可怕:
(ns other-helper)
(defn trivial-stuff [client name bla]
(let [get-something (client :get-something)]
(get-something name))) ; make things like filtering and that
(defn more-trivial-stuff [client name bla]
(let [get-something (client :get-something)])
(get-something name)) ; make things like filtering and that
(defn non-trivial-stuff [client name bla]
(->>
(trivial-stuff client name bla)
(more-trivial-stuff client name)))
(defn more-non-trivial-stuff [client name bla]
(->>
(trivial-stuff client name bla)
(more-trivial-stuff client name)))
(defn compile-utils [client]
{:more-non-trivial (partial more-non-trivial-stuff client)
:non-trivial (partial non-trivial-stuff client)})
我无法为客户端制作任何 def
,因为我将在运行时需要凭据,所以我必须接受所有这些东西作为参数并绑定(bind)结果,对我来说这看起来像大量样板代码和重复代码根本无法维护。
clojurians 有更好的方法吗?在这方面有任何风格指南吗?这是我第二次接触 clojurescript,起初它看起来非常吸引人,但一旦你开始构建重要的东西,它就会开始变得困惑。
注意:为了简单起见,我没有管理任何 js 互操作或使用 channel 进行异步处理。我只是将 js 对象声明为普通的 cljs 映射并将所有内容都视为同步的,但是包括 js 互操作和所有这些东西会使事情变得更糟。
编辑(澄清):
我的问题不是这在 clojure 上是否可行,我知道这是可能的,因为 CLJS 和 JS 共享所需的功能集以使其成为可能。然而,在完全不同的语言上使用相同的模式不仅感觉不对,而且由于 lisp 语法,它看起来也很难看。我能想到的其他替代方案看起来也很丑陋,并且涉及大量重复,因为它需要让客户使用它并在每个函数上传递它,这会导致非常重复和分散注意力的代码。
为了弄清楚我将如何在 js 上使用它,它会像这样
const makeClient = require('./my-http')
const client = makeClient('my-user','my-pass','http://google.es')
client.getSomething('dude')
如您所见,我可以根据需要创建具有不同设置的客户端,我什至可以进行一些解构并仅选择我需要的方法,因为它们根本不依赖于它们的绑定(bind)。
最佳答案
注意:我还没有“愤怒地”使用过 Clojure/Script,所以这对我来说也是一种学习经历 :) 不幸的是,我还没有在 REPL 中验证代码。
如果我没理解错的话,JS模块模式就是一个函数,返回两个函数的字典。在你的代码中的某个时刻,你“创建”了这个模块,也许给它一个名字,然后你在你的代码中传递它,就像这样:
let client = require("mymodule")("user", "pass", "http://example.com");
client.getSomething("foo")
您可以使用 ClojureScript 做同样的事情:
(defn create-client [user pass base]
(let [get-something (fn [name] ...)
create-something (fn [name other] ...)]
{:get get-something :create create-something}))
(let [client (create-client "user" "pass" "http://example.com")]
((client :get) "foo"))
现在可以说这可能看起来有点笨拙,但它是完全相同的代码:关闭几个变量,将两个函数粘贴在一个映射中,从映射中获取一个函数并调用它。
你的问题的第二部分看起来是关于全局状态的——你必须随身携带 client
对象,而且感觉很笨重。我不认为它在 Javascript 中看起来更好?
let client = require("mymodule")("user", "pass", "http://example.com");
let trivialStuff = (client, name, blah) => { client.getSomething(name); ... };
let moreTrivialStuff = (client, name, blah) => { client.getSomething(name); ... };
let nonTrivialStuff = (client, name, blah) => {
let result = trivialStuff(client, name, blah)
return moreTrivialStuff(client, name, result)
}
即您仍在传递 client
。您可以在初始化后使其成为模块级变量,但随后您将失去在运行时创建两个不同客户端的能力。
您是说使用揭示模块模式还会公开 nonTrivialStuff
,因此您可以执行 client.nonTrivialStuff()
?
如何创建一个 namespace ,其中包含所有需要client
的函数(它可能只是一个包含 JS requests
客户端的普通映射),并直接使用它们?
例如
(ns some-client [:require ["request" :as request]])
(defn make-client [usr pass base-url]
{:client (.defaults request {:auth {:user usr :pass pass} :baseUrl baseUrl})}) ;; you might want to use #js here, since you usually cannot pass CLJS maps to JS directly
(defn get-something [client name]
(.get (client :client) (str "resources/" name)))
(defn create-something [client name options]
(.post (client :client) (str "resources") {:name name :data options}))
然后在其他命名空间中:
(ns other-code [:require [some-client :as client]])
(def c (atom nil))
;; get user and pass from runtime, then call
(reset! c (client/make-client user pass base-url))
;; use like so
(client/get-something @c "name")
我选择将 JS 客户端对象放入 CLJS 映射中以实现灵 active ——将来您可能希望将更多数据添加到该映射中。当然,客户端代码不会更改,因为它应该将其视为不透明值。
关于javascript - clojurescript 相当于 javascript 的模块模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49611955/
如何从 clojurescript 程序中获取我所在的 Clojurescript 命名空间?我想这样做确实提供了某些调试信息(它只需要在开发模式下工作) 最佳答案 命名空间在 ClojureScri
我正在考虑使用 ClojureScript 构建一个网站。在客户端和服务器端都编写 ClojureScript 是否有意义,就像 node.js 一样? 最佳答案 这是可能的,但绝对没有理由不在服务器
我正在与Om合作,但我不完全理解以下表达式: (.. e -target -checked) 在这里,“ e”是一个JavaScript事件,“-target -checked”是一种访问属性的方式
我想在 ClojureScript 中前向声明一个函数。种 (defn a [] (b)) ... (defn b [] ...) 我觉得在用法(b)前面放一个(def b nil)是个什么样的作品,
我想在 ClojureScript 中前向声明一个函数。种 (defn a [] (b)) ... (defn b [] ...) 我觉得在用法(b)前面放一个(def b nil)是个什么样的作品,
我不知道像 this 这样的“自托管”clojurescript 实现如何和 this被实现。 但是,鉴于 clojurescript 编译器是用 clojure 编写的并将 clojure 编译为
考虑以下假设的无意义的 ClojureScript 函数: (defn tmp [] (def p 0) (set! p (inc p)) (set! p (inc p)) (set!
我在生产构建部分遇到问题 ClojureScript quickstart .具体来说,当我运行时:java -cp "cljs.jar;src" clojure.main release.clj我得
我正在尝试使用 defmacro在 ClojureScript 中,但出现控制台错误: TypeError: 'undefined' is not an object (evaluating 'crd
我正在寻找一种在 clojureScript 中根据字符串名称调用函数的方法。 就像是: (call "my-fun" args) 欢迎任何帮助 最佳答案 一个应该有效的非常hackish的解决方案:
在 Ubuntu 10.04.1 LTS 上的 FireFox 5.0 中运行的 ClojureScript 程序中,当抛出异常时,我得到一条神秘的线。 '错误:没有为类型对象定义协议(protoco
我正在努力工作 FormidableLabs/radium · GitHub与 reagent-project/reagent · GitHub ,但我已经走到了死胡同。 我能够通过“破解”试剂功能使
是否可以将 Google Closure Templates 与 Clojurescript 一起使用? 我环顾四周,但没有找到任何有关此的信息。 最佳答案 由于 Soy 模板已编译为 JavaScr
我想从 clojurescript 设置 element.style.height 属性,但不幸的是这段代码失败了: (set! (-> (sel1 tr :.ragslide) .-style .-
我正在使用 ClojureScript 编写一些原子(编辑器)包。我遇到了依赖加载问题。 编译后的 ClojureScript 生成如下文件 (main.js): goog.addDependency
我正在为 clojurescript 库编写一些 cljs.test 测试,并且有一些我想加载的 JSON 测试数据。 我不确定我可以使用什么函数来从项目的本地文件加载数据。 我正在使用 lein-d
我有一个从 Leiningen 启动的 ClojureScript 应用程序。我如何在应用程序启动时将环境变量传递给应用程序(可能是它构建时) 最佳答案 有两个构建时间选项: 使用宏 CLJS 宏是
如何在 ClojureScript 中获取时间戳,类似于 Unix 的时间戳,即表示当前时间和日期的单个数字,作为数字。我知道: if (!Date.now) { Date.now = fun
我需要使用 ClojureScript 打开一个新选项卡。 (js/window.open "http://localhost/go/somewhere") 我收到以下错误:未捕获类型错误:windo
我已经阅读了 David Nolen 的基本 Om 教程,但我仍然对应用程序状态和组件本地状态之间的区别感到有些困惑。当引用游标时,它是否也引用了其中之一或两者? 最佳答案 据我了解: 应用程序状态是
我是一名优秀的程序员,十分优秀!