5

How can I call a function named apply() defined on a Javascript object from Scala.js code?

The obvious solution does not work since apply is always compiled into a function call on its parent object by Scala.JS (?):

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
5
  • A slight aside, but if possible avoid calling a function apply unless you definitely want to overwrite the default apply behaviour: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… Commented Aug 19, 2014 at 10:11
  • thanks for the hint; however, I don't want to call apply() on a function, but on an object. Commented Aug 19, 2014 at 10:31
  • In JavaScript an object is a function. Pop up your favourite console and type Object instanceof Function if you're not sure. Of course, the reverse is also true. Expecting JavaScript to behave like a classical Object Oriented language will result in confusion sooner or later. stackoverflow.com/questions/7018023/… Commented Aug 19, 2014 at 10:42
  • well, the console in Chrome replies with "TypeError: object is not a function" when I do this: test = { apply: function() {} }; test() Commented Aug 19, 2014 at 10:57
  • Here test is an anonymous object - which is indeed not a function - but also cannot be instantiated or called because you have declared it as a variable rather than an object. So you can call test.apply() but test is the name of the variable not the name of a type. Commented Aug 19, 2014 at 12:05

1 Answer 1

5

You can annotate the apply method in your facade type with @JSName("apply"). This will yield the desired behavior:

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

Testing:

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

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

For the dynamically typed case, you'll have to invoke applyDynamicNamed manually:

val dyn = test.asInstanceOf[js.Dynamic]

dyn.applyDynamicNamed("apply")(1) // -> 1
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.