接受参数的 JavaScript 范围的 ClojureScript 等价物是什么
What is the ClojureScript equivalent of a JavaScript scope taking an argument
我想编写一个程序,向 div 添加复杂的行为(例如,考虑某种交互式图形)。我希望能够将 div 传递给库中的函数,并让库向 div.
添加行为
如果我在 JavaScript 中这样做,我会写以下内容。
在my_page.html
中:
<div id="program-container"></div>
<script src="my_library.js" type="text/javascript"></script>
<script type="text/javascript">
useDivForACoolProgram(document.getElementById("program-container"));
</script>
在my_library.js
中:
function useDivForACoolProgram(div) {
var x = 2;
var y = 3;
function setup() {
div.innerHTML = "Getting ready to run...";
doMainSetup();
}
function doMainSetup() {
...
// Lots more functions, many of which refer to div
}
请注意,该库公开了一个接受 div 的函数。当我们向它传递 div 时,该库将其所有状态保存在与传递的 div 关联的闭包中,这可能允许我将此行为添加到许多 div 上如果我愿意的话,请翻页。
我想在 ClojureScript 中做同样的事情。我的第一次尝试如下:
(defn use-div-for-a-cool-program [div]
(def x 2)
(def y 3)
(defn setup []
(set! (.innerHTML div) "Getting ready to run...")
(do-main-setup))
(defn do-main-setup []
...
;; Lots more functions, many of which refer to div
)
但这行不通,因为 def
和 defn
在模块范围内定义变量,而不是在 use-div-for-a-cool-program
本地定义变量。如果我用不同的 div 多次调用 use-div-for-a-cool-program
,所有新的 def
和 defn
每次都会覆盖旧的。
一个解决方案是使用 let
代替,但这有点不令人满意,因为它迫使我们在函数被引用之前给出函数的实现,而且也很难阅读,例如
(defn use-div-for-a-cool-program [div]
(let [x 2
y 3
do-main-setup (fn []
...)
setup (fn []
(set! (.innerHTML div) "Getting ready to run...")
(do-main-setup))
;; Lots more functions, many of which refer to div
]
(setup)))
有没有更好的解决方案?
我的解决方案不是您想听到的:) 您将 div
作为参数传递给每个函数。您不是隐式地将函数耦合到 div
,而是明确指定需要 div:
(defn do-main-setup [div]
...)
(defn setup [div]
(set! (.innerHTML div) "Getting ready to run...")
(defn use-div-for-a-cool-program [div]
(let [x 2
y 3]
(do-main-setup div))
;; Lots more functions, many of which refer to div explicitly
(setup div)))
即使这有点冗长(因为您每次都通过 div
),但它使您的意图更加明确。当我想 return 函数并稍后调用它时,我使用闭包,记住它被定义的范围。我看不出将这些函数定义为闭包并在之后精确调用它们有何帮助。
如果您想保持与您的 div
相关联的某些状态,我也会明确地这样做。例如,如果您想统计 div 收到的点击次数,我会这样做:
(defn add-state-handler [div state]
(set! (.onclick div) #(swap! state inc)))
(defn use-div-for-a-cool-program [div]
(let [x 2
y 3
counter (atom 0)]
(do-main-setup div))
(add-state-handler div counter)
;; Other functions that reference div and counter
(setup div)))
简而言之,我会避免隐式处理任何状态或可变值(counter
或 div
)。如果你必须渲染一个依赖于一些变化状态的视图,我会推荐任何 Clojurescript React 包装器,比如 Om or Reagent.
我想编写一个程序,向 div 添加复杂的行为(例如,考虑某种交互式图形)。我希望能够将 div 传递给库中的函数,并让库向 div.
添加行为如果我在 JavaScript 中这样做,我会写以下内容。
在my_page.html
中:
<div id="program-container"></div>
<script src="my_library.js" type="text/javascript"></script>
<script type="text/javascript">
useDivForACoolProgram(document.getElementById("program-container"));
</script>
在my_library.js
中:
function useDivForACoolProgram(div) {
var x = 2;
var y = 3;
function setup() {
div.innerHTML = "Getting ready to run...";
doMainSetup();
}
function doMainSetup() {
...
// Lots more functions, many of which refer to div
}
请注意,该库公开了一个接受 div 的函数。当我们向它传递 div 时,该库将其所有状态保存在与传递的 div 关联的闭包中,这可能允许我将此行为添加到许多 div 上如果我愿意的话,请翻页。
我想在 ClojureScript 中做同样的事情。我的第一次尝试如下:
(defn use-div-for-a-cool-program [div]
(def x 2)
(def y 3)
(defn setup []
(set! (.innerHTML div) "Getting ready to run...")
(do-main-setup))
(defn do-main-setup []
...
;; Lots more functions, many of which refer to div
)
但这行不通,因为 def
和 defn
在模块范围内定义变量,而不是在 use-div-for-a-cool-program
本地定义变量。如果我用不同的 div 多次调用 use-div-for-a-cool-program
,所有新的 def
和 defn
每次都会覆盖旧的。
一个解决方案是使用 let
代替,但这有点不令人满意,因为它迫使我们在函数被引用之前给出函数的实现,而且也很难阅读,例如
(defn use-div-for-a-cool-program [div]
(let [x 2
y 3
do-main-setup (fn []
...)
setup (fn []
(set! (.innerHTML div) "Getting ready to run...")
(do-main-setup))
;; Lots more functions, many of which refer to div
]
(setup)))
有没有更好的解决方案?
我的解决方案不是您想听到的:) 您将 div
作为参数传递给每个函数。您不是隐式地将函数耦合到 div
,而是明确指定需要 div:
(defn do-main-setup [div]
...)
(defn setup [div]
(set! (.innerHTML div) "Getting ready to run...")
(defn use-div-for-a-cool-program [div]
(let [x 2
y 3]
(do-main-setup div))
;; Lots more functions, many of which refer to div explicitly
(setup div)))
即使这有点冗长(因为您每次都通过 div
),但它使您的意图更加明确。当我想 return 函数并稍后调用它时,我使用闭包,记住它被定义的范围。我看不出将这些函数定义为闭包并在之后精确调用它们有何帮助。
如果您想保持与您的 div
相关联的某些状态,我也会明确地这样做。例如,如果您想统计 div 收到的点击次数,我会这样做:
(defn add-state-handler [div state]
(set! (.onclick div) #(swap! state inc)))
(defn use-div-for-a-cool-program [div]
(let [x 2
y 3
counter (atom 0)]
(do-main-setup div))
(add-state-handler div counter)
;; Other functions that reference div and counter
(setup div)))
简而言之,我会避免隐式处理任何状态或可变值(counter
或 div
)。如果你必须渲染一个依赖于一些变化状态的视图,我会推荐任何 Clojurescript React 包装器,比如 Om or Reagent.