2015-01-21 65 views
0

我想編寫一個程序,爲div添加複雜行爲(例如,考慮某種交互式圖形)。我想能夠將一個div傳遞給庫中的一個函數,並讓該庫爲div添加行爲。什麼是ClojureScript等效於採用參數的JavaScript作用域

如果我在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 
) 

但是,這並不工作,因爲defdefn定義在模塊的範圍內的變量,而不是定義局部變量use-div-for-a-cool-program。如果我用不同的divs多次呼叫use-div-for-a-cool-program,則所有新的def s和defn s都會覆蓋舊的每次。

一種解決方案是使用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))) 

有沒有更好的解決方案?

回答

1

我的解決方案不是你想要的:)你將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)它使你的意圖明確。當我想要返回函數並在稍後調用它時使用閉包,並記住它的定義範圍。我不明白將這些函數定義爲閉包並在之後精確地調用它們有什麼用處。

如果你想保留一些與你的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))) 

總之,我會避免隱式處理任何國家或可變值(counterdiv)。如果你必須渲染一個取決於一些改變狀態的視圖,我會推薦任何Clojurescript React包裝器,如OmReagent

+0

我喜歡你在這裏想要做的,但是假設我的程序帶有狀態。作爲一個簡單的例子,假設我想跟蹤div被點擊了多少次。如果我用閉包來做這件事,我會在閉包中保留一個可變變量,這樣我的所有函數都可以引用它,並且每個div都會自動獲取它自己的變量。你的榜樣在哪裏保持這種狀態? – dphilipson 2015-01-21 19:07:23

相關問題