2015-01-21 1 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 
) 

Но это не работает, потому что def и defn определяют переменные в области видимости модуля, а не определение локальных переменных в use-div-for-a-cool-program. Если бы я должен был называть use-div-for-a-cool-program несколько раз с разными div, все новые 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, я бы тоже сделал это явно. Например, если вы хотите сохранить счет, сколько кликов по ДИВ получили бы я это сделать:

(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 или Reagent.

+0

Мне нравится то, что вы пытаетесь сделать здесь, но предположите, что моя программа несет в себе состояние. В качестве простого примера предположим, что я хочу отслеживать, сколько раз был нажат div.Если бы я делал это с закрытием, я бы сохранил измененную переменную в закрытии, поэтому все мои функции могли бы ссылаться на нее, и каждый div автоматически получит свою собственную переменную. Где бы вы сохранили это состояние в своем примере? – dphilipson

Смежные вопросы