首页 > 解决方案 > scala.js 1.0 中的@JSGlobalScope(JavaScriptException、ReferenceError、var 未定义)

问题描述

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

我的用例是这样的:

代码如下所示:

  @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

1.0.0 的更新日志中有一个“重大更改”部分提到了这一点:

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

js.Dynamic.global.globalVarThatDoesNotExist = 42

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

我的问题是:

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

标签: scalascala.js

解决方案


如果您知道您将始终处于浏览器上下文中,则可以使用@JSGlobal("window")而不是@JSGlobalScopeon your Globals,这将等效于window.myGlobalVarFor3rdPartyLib在 JS 中执行。所以这会奏效。

@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 尝试为您执行此操作,但可能会失败,因此我们不再执行此操作。您至少可以按照文档中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。如果您的代码需要在这样的环境中运行,则由您决定使用适当的检测程序。


推荐阅读