能否将JavaScript方法当作ClojureScript函数使用?附日期计算代码问题
问题解答
你的报错核心原因是:在ClojureScript中,.getSeconds、.setSeconds这类写法是方法调用的语法糖,并不是可以直接赋值和调用的函数对象。直接把它们当作函数使用会导致CLJS无法正确解析,从而抛出错误。
修正方案:用匿名函数包裹方法调用
把每个unit对应的getter和setter改成匿名函数,让它们能接收date参数并执行对应的方法调用:
(defn date-add [date num unit] (let [[getter setter] (case unit :sec [#(.getSeconds %) #(.setSeconds %1 %2)] :min [#(.getMinutes %) #(.setMinutes %1 %2)] :hour [#(.getHours %) #(.setHours %1 %2)] :day [#(.getDate %) #(.setDate %1 %2)] :month [#(.getMonth %) #(.setMonth %1 %2)] :year [#(.getFullYear %) #(.setFullYear %1 %2)])] (setter date (+ num (getter date))) (js/Date. (.getTime date))))
另一种方案:从原型获取方法并绑定上下文
如果想直接使用JS方法的函数引用,需要从js/Date.prototype上获取方法,并且调用时绑定date对象作为this(因为JS方法依赖当前实例作为上下文):
(defn date-add [date num unit] (let [[getter setter] (case unit :sec [(. js/Date.prototype -getSeconds) (. js/Date.prototype -setSeconds)] :min [(. js/Date.prototype -getMinutes) (. js/Date.prototype -setMinutes)] :hour [(. js/Date.prototype -getHours) (. js/Date.prototype -setHours)] :day [(. js/Date.prototype -getDate) (. js/Date.prototype -setDate)] :month [(. js/Date.prototype -getMonth) (. js/Date.prototype -setMonth)] :year [(. js/Date.prototype -getFullYear) (. js/Date.prototype -setFullYear)])] (.call setter date (+ num (.call getter date))) (js/Date. (.getTime date))))
这种方式需要用.call来指定方法执行的上下文(即date对象),否则JS方法会因为this指向错误而失效。
补充说明
- 第一种匿名函数的方式更符合CLJS的编写习惯,代码可读性更高,也不需要处理上下文绑定的问题。
- 你创建新
js/Date实例的做法是对的,因为JS的set*方法会修改原date对象,返回新实例可以避免副作用。
内容的提问来源于stack exchange,提问作者hata
相关产品推荐
相关产品推荐

