动态访问 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。特别是,您似乎希望能够加载扩展 Res
的 object
给定它们的名称,这正是 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"))
请注意,您需要使用对象的完全限定名称。
我的 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。特别是,您似乎希望能够加载扩展 Res
的 object
给定它们的名称,这正是 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"))
请注意,您需要使用对象的完全限定名称。