Scala.js does not have an equivalent of the arguments.callee of JavaScript. More generally, it does not have an equivalent of arguments. So a lambda cannot read a reference to itself, unless it is given to it via its captured environment. This can be achieved by storing the lambda in a val in the once method. Ideally, one would like to write this:
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))
}
However, this won't compile, because you cannot use a val (here cb) in the right-hand-side of its definition, even if that happens to be inside a lambda. Trying to do so results in the following compile error:
Main.scala:17: error: forward reference extends over definition of value cb
e.target.removeEventListener(e.`type`, cb) // using cb here
There is a simple solution, though: use a lazy val instead:
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))
}
Make sure to declare cb as a js.Function1, not a Function1. Otherwise cb itself would refer to the Scala function, but not the JS function resulting from the automatic conversion (which have different identities). You have to make sure cb refers to the JS function.
Fiddle: http://www.scala-js-fiddle.com/gist/2b848e2f01e7af522dc1