I am trying to call a function in Javascript from Java/Nashorn (in Scala, but that's not material to the question).
// JS
var foo = function(calculator){ // calculator is a Scala object
return this.num * calculator.calcMult();
}
The context on the Scala side is like this:
case class Thing(
num: Int,
stuff: String
)
case class Worker() { // Scala object to bind to calculator
def calMult() = { 3 } // presumably some complex computation here
}
I start by getting foo into the JS environment:
jsengine.eval("""var foo = function(calculator){return this.num * calculator.calcMult();}"""
To use this I need two things to be available: 1) 'this' context to be populated with my Thing object, and 2) the ability to pass a Java/Scala object to my JS function (to call calcMulti later). (If needed I can easily JSON-serialize Thing.)
How can I do both and successfully call foo() from Scala?
This may not be the only or cleanest solution, but it does work.
Turns out javascript has the ability to bind a given 'this' context to a function, which creates a "bound function" that has your 'this' visible within it. Then you use invoke() as you normally would on the bound function.
val inv = javascript.asInstanceOf[Invocable]
val myThis: String = // JSON serialized Map of stuff you want accessible in the js function
val bindFn = "bind_" + fnName
javascript.eval(bindFn + s" = $fnName.bind(" + myThis + ")")
inv.invokeFunction(bindFn, args: _*)
If you passed myThis into the binding to include {"x":"foo"}
then when invoked, any access within your function to this.x
will resolve to "foo" as you'd expect.