Clojurescript添加事件监听器

6
(defn domready [handler]
  (.addEventListener js/window "DOMContentLoaded" handler))

我从这里借用了这段代码。问题是我不完全明白正在发生什么事情。JS互操作对我来说仍然有点神秘。

  1. .addEventListener

所以这显然是一个过程调用,但它有点通用。就像Clojurescript把对象中的所有内容都取出来,然后你可以用它来调用“对象”上的该方法一样。只要那个“对象”有“.addEventListener”属性,它就会调用这个方法。这是它在做什么吗?为什么不使用关键字呢?比如(:addEventListener domElement),这对我来说似乎更合理。

  1. js/window

这是什么?它是一个命名空间还是一个对象?它们是同一种东西吗?

  1. "DOMContentLoaded"

一个字符串,很熟悉。

  1. handler

也很熟悉,但它是否有this的概念?并不是我真的会想念this


你可以使用 this-as 宏来处理 this - Michiel Borkent
1
这是我为教授interop编写的教程之一:http://chimeces.com/cljs-browser-repl/#/notebook/diving-into-clojurescript/file/9 希望它能帮到你。我会回答你的问题并提供答案。 - Joaquin
为了避免混淆,.addEventListener 是一个方法调用。还有一种属性的概念,使用 .-(句点和减号/破折号)访问。在面向对象编程中,我想你会说 (.method obj) 运行对象方法,而 (.-property obj) 访问对象中的属性/变量。 - Tim X
3个回答

7

.addEventListener

这显然是一个过程调用,但它有点通用。就像Clojurescript将对象中的所有内容都取出来一样,并使用它来调用“对象”上的该方法。只要该“对象”具有“.addEventListener”属性,它就会调用此方法。这是它在做什么吗?为什么不使用关键字呢?例如(:addEventListener domElement),我觉得这更合理。

您对其工作方式的心理模型大多正确。编译时,它将要运行的函数名称移动到第一个参数上作为方法。

(.method obj ...args) 被转换为 obj.method(...args)

这种互操作性来自父语言Clojure。

关于为什么我们有一个明确的调用函数版本而不是Clojure惯用语,我认为这个想法是要在本地Clojure代码和Clojure语义(不可变性,友好的CLJ数据结构等)与与主机环境进行交互的代码之间保持清晰的分离(可变性,不友好的CLJ数据结构等)。

在我看来,鉴于CLJS和主机平台的语义差异如此之大,最好在这两者之间有明确的分离。对我来说,在这种情况下,明确比隐含更好(很容易在代码中看到什么是CLJS中的JS代码以及什么是纯粹的CLJS)。

js/window

这是什么?它是一个命名空间还是一个对象?它们是一样的吗?

两者都是,js/正在访问命名空间js,这是CLJS放置JS命名空间的位置(因为只有一个和全局的)。 window只是从js命名空间中获取window变量。

这与您在CLJS中访问其他命名空间中的变量的方式没有区别。如果您在(ns cljs.test)(def a 1),然后运行cljs.test/a,那么这将给您1。同样的形式,ns / something-in-that-ns

"DOMContentLoaded" 一个熟悉的字符串。

\o/

handler

也很熟悉,但它是否具有this的概念?我不会真正错过这个。

不确定thishandler有什么关系。它只是作为参数传递给domready的高阶函数,就像您在JS中所做的那样:function domready (onReady) { window.addEventListener("DOMContentLoaded", onReady) }


希望这能帮到你,如果你想亲身尝试并学习更多,可以访问Diving into ClojureScript教程中的Talking with JS部分,或者查看这个lt-cljs-tutorial的章节


非常感谢你这么出色的回答! - Breedly

3

我正在学习ClojureScript,所以不确定以下是否是正确答案,但我是用以下方式完成的:

(defn handler [] (js/console.log "ready"))
(js/document.addEventListener  "DOMContentLoaded" handler)

这将被翻译为:

cljs.user.handler = (function cljs$user$handler(){
  return console.log("ready");
});
document.addEventListener("DOMContentLoaded",cljs.user.handler);

我使用KLIMPSE http://app.klipse.tech/ 来检查ClojureScript代码的翻译效果。


1
Klipse真的很棒,可以帮助我们了解幕后发生了什么,感谢分享。 - Pedro Henrique

2

.addEventListener是在全局Javascript对象js/window上调用的方法。这个方法需要传递两个参数:"DOMContentLoaded"handler

当进行互操作(无论是Java还是Javascript),实际上是在调用对象的方法。这里发生的事情背后有宏。紧跟着(的是一个动词,我通常认为它是一个函数调用(虽然它也可能是宏或特殊形式)。在进行互操作时,动词之后的是实例,之后是参数。

如果是纯Javascript,代码将如下所示:

function domready(handler){
    window.addEventListener("DOMContentLoaded" handler);
}

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