我正在尝试将cloout.js包裹在clojurescript中,但它变得非常困难。我遇到的问题是对'this'变量的引用。我正在考虑放弃并直接使用javascript。
我已经从http://knockoutjs.com/examples/helloWorld.html和http://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())
有什么想法吗?
答案 0 :(得分: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对象的最佳方法是定义一个__init__
方法,将其添加到类中然后运行它,然后删除它来自课堂。例如,如果我想创建另一个对象:
var avobj = {a: this,
b: 98,
c: this.a
get_a: function(){return str(this.a) + str(this.c);}};
用clo和__init__
方法写成clojurescript,如下所示:
(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__")))
并使用map-&gt; js取自jayq.utils:
(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并且完全可读!
答案 1 :(得分:2)
如果您需要明确引用JavaScript this
动态绑定,ClojureScript会提供this-as
宏:
https://github.com/clojure/clojurescript/blob/master/src/clj/cljs/core.clj#L324