如何从Scala.js调用Javascript的apply()方法?

5
我该如何从Scala.js代码中调用一个名为apply()的Javascript对象上定义的函数?
显然的解决方案不起作用,因为Scala.js总是将apply编译成其父对象上的函数调用。
var test = {
  apply: function(idx) {...},
  apple: function(idx) {...}
}

trait Test extends js.Object {
  def apple(idx: Int) : Int = ???
  def apply(idx: Int) : Int = ???
}

val test = js.Dynamic.global.test.asInstanceOf[Test]

test.apple(1) // works, of course

test.apply(1) // does not work (seems to be compiled into the call test(1) ?)

js.Dynamic.global.test.apply(1) // does not work either

稍微离题一下,但如果可能的话,请避免将函数命名为 apply,除非您确实想要覆盖默认的 apply 行为:http://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply - glenatron
谢谢你的提示;然而,我不想在一个函数上调用apply(),而是在一个对象上调用。 - jokade
在 JavaScript 中,对象 就是 函数。如果您不确定,请打开您最喜欢的控制台并键入“Object instanceof Function”。当然,反之亦然。期望 JavaScript 像经典面向对象语言一样运作将会导致迟早的混乱。https://dev59.com/ylrUa4cB1Zd3GeqPhCMB - glenatron
当我这样做时,Chrome控制台会回复“TypeError:object is not a function”:test = { apply: function() {} }; test() - jokade
这里的 test 是一个匿名对象 - 它确实不是一个函数 - 但也不能被实例化或调用,因为你将它声明为一个变量而不是一个对象。所以你可以调用 test.apply(),但 test 是变量的名称,而不是类型的名称。 - glenatron
1个回答

5

您可以在门面类型的apply方法上注释@JSName("apply")。这将产生所需的行为:

trait Test extends js.Object {
  def apple(idx: Int) : Int = ???
  @JSName("apply")
  def apply(idx: Int) : Int = ???
}

测试:

val test = js.Dynamic.literal(
    apply = (idx: Int) => idx,
    apple = (idx: Int) => idx
).asInstanceOf[Test]

test.apple(1) // -> 1
test.apply(1) // -> 1

对于动态类型情况,你需要手动调用applyDynamicNamed

val dyn = test.asInstanceOf[js.Dynamic]

dyn.applyDynamicNamed("apply")(1) // -> 1

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