动态访问Scala.js中的命名对象

时间:2018-09-21 19:28:50

标签: scala scala.js

我的Scala.js项目中有一些对象我想动态访问。我想我可以使用Dynamic来使它工作,但是目前fastOptJS / fullOptJS步骤正在丢弃它们。有什么方法(注释?)我可以将它们标记为必需的,而在优化过程中永不丢弃?

我不想在任何地方列出它们,因为它们在我的应用程序中有数百个,并且经常被添加/删除。

示例:

trait Res {def value;}
object A {def value = "A...";}
object B {def value = "B...";}

def loadAB(name: String): String {
  scala.scalajs.js.Dynamic.global.selectDynamic(name).asInstanceOf[Res].value
}

2 个答案:

答案 0 :(得分:2)

您无法通过object访问Scala.js中定义的js.Dynamic.global,因为默认情况下Scala.js不会在global中放置任何内容。它只将带有@JSExportTopLevel的内容导出到其中。

@Simon Groenewolt建议了基于@JSExportTopLevel的解决方案,但这是您的情况下性能欠佳的黑客。确实,这将迫使这些对象中的每个对象都在JavaScript全局范围内公开,这不好,因为它们可能会被JavaScript篡改(或篡改其他JavaScript库)。

此外,如果您(或您的家属)发出CommonJS模块,则该黑客将停止运行。在Scala.js 1.x中,如此也将不再起作用,因为将不再允许从global进行动态选择(您必须事先自己动态查找全局对象) )。

针对您的用例的更好解决方案似乎是Reflect API。尤其是,您似乎希望能够加载给定名称的object扩展了Res的{​​{1}},假设您注释了Reflect,这正是Res给您的名字与@EnableReflectiveInstantiation

package foo

import scala.scalajs.reflect.Reflect
import scala.scalajs.reflect.annotation.EnableReflectiveInstantiation

@EnableReflectiveInstantiation
trait Res {def value;}

object A {def value = "A...";}
object B {def value = "B...";}

def loadAB(name: String): String {
  Reflect
    .lookupLoadableModuleClass(name + "$")
    .getOrElse(throw new Exception("hum, that as not found")
    .loadModule()
    .asInstanceOf[Res]
    .value
}

println(loadAB("foo.A"))

请注意,您需要使用对象的完全限定名称。

答案 1 :(得分:1)

也许用@JSExportTopLevel(<identifier>)注释它们会达到预期的效果吗?这是针对exporting to JavaScript的,但具有防止捆绑时丢弃代码的副作用。