【问题标题】:@JSGlobalScope in scala.js 1.0 (JavaScriptException, ReferenceError, var is not defined)scala.js 1.0 中的@JSGlobalScope(JavaScriptException、ReferenceError、var 未定义)
【发布时间】:2020-03-19 18:49:18
【问题描述】:

从 scala.js 0.6.x 迁移到 1.0 后,我有一些与 @JSGlobalScope 相关的代码损坏。

我的用例是这样的:

  • 有一个第 3 方库需要将一些全局变量设置为函数
  • 加载并准备就绪后,它会调用此函数(按名称)
  • 我在 scala.js 的全局范围内设置了这个函数

代码如下:

  @js.native
  @JSGlobalScope
  object Globals extends js.Object {
    var callbackFunctionFor3rdPartyLib: js.Function0[Unit] = js.native
  }

然后我像这样设置这个变量:

Globals.callbackFunctionFor3rdPartyLib = () => {
   // do things
}

然后我将脚本添加到 DOM 中。

这适用于 scala.js 0.6.x,但对于 1.0,我遇到如下异常:

scala.scalajs.js.JavaScriptException: ReferenceError: callbackFunctionFor3rdPartyLib is not defined

changelog for 1.0.0 中有一个“重大更改”部分提到了这一点:

访问未声明的成员会导致抛出 ReferenceError ...

js.Dynamic.global.globalVarThatDoesNotExist = 42

之前会创建所述全局变量。在 Scala.js 1.x 中,它还会引发 ReferenceError。

我的问题是:

在 scala.js 1.0 中做这样的事情(创建一个新的全局变量)的正确方法是什么?

【问题讨论】:

    标签: scala scala.js


    【解决方案1】:

    如果您知道您将始终处于浏览器上下文中,则可以在 Globals 上使用 @JSGlobal("window") 而不是 @JSGlobalScope,这相当于在 JS 中使用 window.myGlobalVarFor3rdPartyLib。这样就可以了。

    @js.native
    @JSGlobal("window")
    object Globals extends js.Object {
      var callbackFunctionFor3rdPartyLib: js.Function0[Unit] = js.native
    }
    

    如果不是,但是您使用的是 脚本(所以不是 CommonJS 也不是 ES 模块),最好的办法是实际使用

    object Globals {
      @JSExportTopLevel("myGlobalVarFor3rdPartyLib")
      var foo: js.Function[Unit] = ...
    }
    

    请注意,Globals 现在是普通的 Scala 对象,而不是 JS 对象。

    @JSExportTopLevel 在脚本顶部创建一个顶级var myGlobalVarFor3rdPartyLib,然后分配Globals.foo 也会分配该顶级var


    如果您不使用脚本也不知道您将始终在浏览器中,那么您需要自己找出全局对象。 Scala.js 0.6.x 尝试为您执行此操作,但可能会失败,因此我们不再执行此操作。您至少可以按照the documentation of js.special.fileLevelThis 上的“说明”来重现 Scala.js 0.6.x 正在做的事情。我在这里重复说明:

    应该很少使用这个值,并且主要限于编写代码 检测全局对象是什么。例如,一个典型的检测 代码——如果我们不需要担心 ES 模块——看起来像:

    val globalObject = {
      import js.Dynamic.{global => g}
      if (js.typeOf(g.global) != "undefined" && (g.global.Object eq g.Object)) {
        // Node.js environment detected
        g.global
      } else {
        // In all other well-known environment, we can use the global `this`
        js.special.fileLevelThis
      }
    }
    

    请注意,上面的代码并不全面,因为可能有 JavaScript 无法通过以下方式获取全局对象的环境 global 也不是 this。如果你的代码需要在这样的环境中运行,它 由您决定使用适当的检测程序。

    【讨论】:

      猜你喜欢
      • 2012-08-24
      • 1970-01-01
      • 2023-01-23
      • 2015-10-04
      • 2017-04-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多