我将此JavaScript函数移植到Scala.js:
once: function (el, type, callback) {
var typeArray = type.split(' ');
for (var i = typeArray.length - 1; i >= 0; i--) {
el.addEventListener(typeArray[i], function(e) {
e.target.removeEventListener(e.type, arguments.callee);
return callback(e);
});
};
},
以下是我编写Scala代码的尝试:
def once(element: TopNode, tpe: String, callback: Function1[Event,Any]): Unit = {
tpe.split(" ").foreach(item => element.addEventListener(item, (e : Event) => {
e.target.removeEventListener(e.`type`, ?) // <-- what do I put here?
callback(e)
}))
}
如何在该占位符中引用我的lambda?
答案 0 :(得分:4)
Scala.js没有等效的arguments.callee
JavaScript。更一般地说,它没有等效的arguments
。因此,lambda无法读取对自身的引用,除非通过其捕获的环境将其赋予它。这可以通过在val
方法中将lambda存储在once
中来实现。理想情况下,人们想写这个:
def once(element: TopNode, tpe: String,
callback: Function1[Event,Any]): Unit = {
val cb: js.Function1[Event, Any] = { (e: Event) =>
e.target.removeEventListener(e.`type`, cb) // using cb here
callback(e)
}
tpe.split(" ").foreach(item => element.addEventListener(item, cb))
}
但是,这不会编译,因为你不能在它的定义的右边使用val(这里是cb
),即使它恰好在lambda中。尝试这样做会导致以下编译错误:
Main.scala:17: error: forward reference extends over definition of value cb
e.target.removeEventListener(e.`type`, cb) // using cb here
但是有一个简单的解决方案:改为使用lazy val
:
def once(element: TopNode, tpe: String,
callback: Function1[Event,Any]): Unit = {
lazy val cb: js.Function1[Event, Any] = { (e: Event) =>
e.target.removeEventListener(e.`type`, cb) // using cb here
callback(e)
}
tpe.split(" ").foreach(item => element.addEventListener(item, cb))
}
请务必将cb
声明为js.Function1
,而不是Function1
。否则cb
本身将引用Scala函数,而不是自动转换产生的JS函数(具有不同的身份)。您必须确保cb
引用JS函数。
小提琴:http://www.scala-js-fiddle.com/gist/2b848e2f01e7af522dc1