5

私はknockout.jsをclojurescriptでラップしようとしていますが、それを変えるのは非常に困難です。私が抱えている問題は、「this」変数への参照です。私はあきらめて、JavaScriptを直接使用することを考えています。

http://knockoutjs.com/examples/helloWorld.htmlhttp://knockoutjs.com/examples/contactsEditor.htmlから例を取り上げました

簡単な関数をいくつかのマクロでラップすることができました。例えば:

var ViewModel = function() {
    this.firstName = ko.observable("Bert");
    this.lastName = ko.observable("Bertington");

    this.fullName = ko.computed(function() {
        // Knockout tracks dependencies automatically. It knows that fullName depends on firstName and lastName, because these get called when evaluating fullName.
        return this.firstName() + " " + this.lastName();
    }, this);
};

になります:

(defviewmodel data
  (observing :first_name "Bert")
  (observing :last_name  "Bertington")
  (computing :name [:first_name :last_name]
    (str :first_name " " :last_name)))

ただし、次のような難しいものの場合:

var BetterListModel = function () {
    this.itemToAdd = ko.observable("");
    this.allItems = ko.observableArray(["Fries", "Eggs Benedict", "Ham", "Cheese"]); // Initial items
    this.selectedItems = ko.observableArray(["Ham"]);                                // Initial selection

    this.addItem = function () {
        if ((this.itemToAdd() != "") && (this.allItems.indexOf(this.itemToAdd()) < 0)) // Prevent blanks and duplicates
            this.allItems.push(this.itemToAdd());
        this.itemToAdd(""); // Clear the text box
    };

    this.removeSelected = function () {
        this.allItems.removeAll(this.selectedItems());
        this.selectedItems([]); // Clear selection
    };

    this.sortItems = function() {
        this.allItems.sort();
    };
};

ko.applyBindings(new BetterListModel());

このようなコードに一致させるためにclojurescriptで何ができるかわかりません:this.allItems.push(this.itemToAdd())

何かご意見は?

4

2 に答える 2

5

試行錯誤の末、clojurescriptとjavascriptの構造を同じにする方法を見つけました。

マクロにはいくつかのthis-as特異性があり、メソッドがクラスに入れられたときにのみ機能します

たとえば、JavaScriptで次のようなものを作成したいと思います。

var anobj = {a: 9,
             get_a: function(){return this.a;}};

clojurescriptで同じオブジェクトを取得するには、さらに多くのコーディングを行う必要があります。

(def anobj (js-obj))
(def get_a (fn [] (this-as me (.-a me))))
(aset anobj "a" 9)
(aset anobj "get_a" get_a)

これは、clojureのように美しい言語にとってはひどく醜いです。ノックアウトで起こることのように、相互にリンクする関数があると、事態はさらに悪化します。

たくさんのthis'が含まれるjs-objectを作成する最良の方法は、メソッドを定義し、__init__それをクラスに追加してから実行し、クラスから削除することです。たとえば、別のオブジェクトを作成したい場合:

var avobj = {a: this,
             b: 98,
             c: this.a
             get_a: function(){return str(this.a) + str(this.c);}};

とメソッドを使用してclojurescriptとして記述されたものは、__init__次のようになります。

(def avobj (js-obj))
(def av__init__ 
     #(this-as this 
        (aset this "a" this) 
        (aset this "b" 9) 
        (aset this "c" (.-a this))
        (aset this "get_a" (fn [] (str (.-a this) (.-c this))))))
(aset avobj "__init__" av__init__)
(. avobj __init__)
(js-delete stuff "__init__")

javascriptよりもまだたくさんのコードがあります...しかし、最も重要なことは、javascriptと同じオブジェクトを取得することです。このフォームを使用してすべての変数を設定すると、マクロを使用して簡略化することもできます。これで、マクロを定義しました。

(defmacro defvar [name & body]
   (list 'do
    (list 'def name
      (list 'map->js 
        {
          :__init__ 
          (list 'fn []
              (list 'this-as 'this
                 (list 'aset 'this "a" "blah")))          
        }))
    ;(. js/console log ~name)
    (list '. name '__init__)
    (list 'js-delete name "__init__")))

jayq.utilsから取得したmap->jsを使用します。

(defn map->js [m]
  (let [out (js-obj)]
    (doseq [[k v] m]
      (aset out (name k) v))
    out))

これで、次のようなコードを記述できます。

(defvar avobj
   a this 
   b 9 
   c (.-a this)
   get_a (fn [] (str (.-a this) (.-c this))))

そしてノックアウトへの答えのために:

(defvar name_model
    first_name (observable "My")
    last_name (observable "Name")
    name (computed (fn [] (str (. this first_name) " " (. this last_name)))))

(. js/ko (applyBindings name_model));

これは、JavaScriptと非常によく一致し、完全に読み取り可能であるため、私にとっては本当に素晴らしいことです。

于 2012-06-07T23:47:08.673 に答える
2

JavaScriptの動的バインディングへの明示的な参照が必要な場合this、ClojureScriptはthis-asマクロを提供します。

https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/core.clj#L324

于 2012-06-05T05:00:17.587 に答える