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

Dynamic access to named objects in Scala.js

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

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

示例:

trait Res {
  def value: String
}
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
}

也许用@JSExportTopLevel(<identifier>)注释它们会达到预期的效果?这适用于 exporting to JavaScript,但会产生防止代码在捆绑时被丢弃的副作用。

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

放在那里

@Simon Groenewolt 建议了一个基于 @JSExportTopLevel 的解决方案,但在您的案例中这是一个具有次优属性的 hack。实际上,它会强制这些对象中的每一个都暴露在 JavaScript 全局范围内,这并不好,因为它们可能会被 JavaScript 篡改(或篡改其他 JavaScript 图书馆)。

此外,如果您(或您的家属)发出 CommonJS 模块,该 hack 将停止运行。在 Scala.js 1.x 中它也将不再 这样 工作,因为不再允许从 global 进行动态选择(你必须动态地而是事先自己找到全局对象)。

您的用例的更好解决方案似乎是 Reflect API。特别是,您似乎希望能够加载扩展 Resobject 给定它们的名称,这正是 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"))

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