@JSGlobalScope в scala. js 1.0 (JavaScriptException, ReferenceError, var не определено) - PullRequest
3 голосов
/ 18 марта 2020

После миграции с scala. js 0.6.x на 1.0 у меня есть код, связанный с @JSGlobalScope неработающим.

Мой пример использования такой:

  • есть сторонняя библиотека, которая ожидает, что для некоторой глобальной переменной будет установлена ​​функция
  • , когда она загружена и готова, она вызывает эту функцию (по имени)
  • Я установил эта функция в глобальной области видимости от 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

В журнале изменений для 1.0.0 есть раздел «Срочные изменения», в котором упоминается:

Доступ к элементу, который не объявлен, вызывает Ошибка ReferenceErtion ...

js.Dynamic.global.globalVarThatDoesNotExist = 42

ранее создала бы указанную глобальную переменную. В Scala. js 1.x также выдается ошибка ReferenceError.

Мой вопрос:

Как правильно сделать что-то подобное (создать новый глобальный var) в scala. js 1.0?

1 Ответ

1 голос
/ 19 марта 2020

Если вы знаете, что вы всегда будете в контексте браузера, вы можете использовать @JSGlobal("window") вместо @JSGlobalScope на вашем Globals, что будет эквивалентно window.myGlobalVarFor3rdPartyLib в JS. Так что это сработает.

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

Если нет, но вы используете скрипт (то есть не Common JS или модуль 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. Если ваш код должен работать в такой среде, вы должны использовать соответствующую процедуру обнаружения.

...