如何在ClojureScript中创建带有方法和构造函数的JS对象

12

假设任务是在ClojureScript中创建一些实用程序库,以便可以从JS中使用它。

例如,假设我想要生成等效的代码:

    var Foo = function(a, b, c){
      this.a = a;
      this.b = b;
      this.c = c;    
    }

    Foo.prototype.bar = function(x){
      return this.a + this.b + this.c + x;
    }

    var x = new Foo(1,2,3);

    x.bar(3);           //  >>  9    

我想到的一种实现方法是:

    (deftype Foo [a b c])   

    (set! (.bar (.prototype Foo)) 
      (fn [x] 
        (this-as this
          (+ (.a this) (.b this) (.c this) x))))

    (def x (Foo. 1 2 3))

    (.bar x 3)     ; >> 9

问题:在ClojureScript中是否有更优雅、更惯用的方式实现上述代码?

2个回答

20

通过添加一个魔法"Object"协议到deftype中,JIRA CLJS-83问题已得到解决:

(deftype Foo [a b c]
  Object
  (bar [this x] (+ a b c x)))
(def afoo (Foo. 1 2 3))
(.bar afoo 3) ; >> 9

2
请注意时间戳。这个答案实际上是在 dnolen 的答案之后发布的,日期是2012年1月26日(大约一年后),而且这个答案看起来更加优雅。 - Greg Slepak

12
(defprotocol IFoo
  (bar [this x]))

(deftype Foo [a b c]
  IFoo
  (bar [_ x]
    (+ a b c x)))

(def afoo (Foo. 1 2 3))
(bar afoo 3) ; >> 9

这是惯用的方式。


谢谢,实际上看起来很符合习惯用法,但你不能从js中调用它(我们正在构建js库):cljs.user.afoo.bar(3)在这里我们可以:cljs.user.x.bar(3)为了从js端使用你的习惯用法版本,需要调用:cljs.user.afoo.cljs$user$IFoo$bar(null, 3)我有什么遗漏吗? - Lambder
@user535149 那其实是另一个问题。如果你想要导出一些东西,使用 (defn ^:export foo [..] ...)。 - dnolen
^: 只有当'something'是一个函数时,'export'才能起作用。我想要导出一个对象,它的方法是在其原型上定义的。 - Lambder
1
那并不是很有用,因为原型上的方法将被命名空间化。 - dnolen
那么,使用ClojureScript创建一个带有构造函数和原型方法的对象的惯用方式是什么?我在原始问题中提出的方式是唯一的吗? - Lambder

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接