2014-12-02 78 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