2014-12-02 49 views
2

我移植这个JavaScript函数Scala.js:arguments.callee的在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) 
    })) 
} 

我如何可以参考我的拉姆达在那个地方持有人?

回答

4

Scala.js没有等效于JavaScript的arguments.callee。更一般地说,它没有相当于arguments。所以lambda不能读取对自身的引用,除非通过其捕获的环境给它。这可以通过将中的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)) 
} 

确保申报cbjs.Function1,不是Function1 。否则cb本身会引用Scala函数,但不是自动转换产生的JS函数(它们具有不同的身份)。您必须确保cb引用JS函数。

小提琴:http://www.scala-js-fiddle.com/gist/2b848e2f01e7af522dc1