Scala.js 在全局范围内没有看到一个 JS *class*,但是看到了一个构造函数

Scala.js does not see a JS *class* in the global scope, but sees a constructor function

在尝试为 javascript class 编写 scalajs facade 时,出现以下错误:"error Uncaught TypeError: $g.MyRect2 is not a constructor" 在 chrome 控制台中。

我的javascriptclass定义如下:

class MyRect2 {
    constructor(height, width) {
        this.height = height;
        this.width = width;
      }

      area() {
      return this.height * this.width
      }

}

然后我在scala中导入如下

@js.native
class MyRect2(h:Int,w:Int) extends  js.Object {

  val height:Int = js.native
  val width:Int = js.native
  def area():Int = js.native
}

最后我实例化了 class 如下

val rect2 = new MyRect2(2,2) //This is giving the above error.

但是,当我如下编写 javascript class 时,相同的导入和实例化工作

function MyRect2(height,width) {
    this.height = height;
    this.width = width;
    this.area = function() {return this.height * this.width;};
}

请指出我做错了什么。

编辑: 这已在 Scala.js 1.x 中修复(截至撰写本文时,Scala.js 1.0.0-M1 已被修复已发布)。

哎哟......好吧,这让我的一天变得更加黑暗。

事实证明 class 声明(与 letconst 一起,但不同于 varfunctions)做 添加它们声明为JavaScript 的全局对象 的属性。它们仅在 全局范围内可用

在 ECMAScript 5.1 之前,这两个东西是等价的:当且仅当它是全局对象的 属性 时,它才在全局范围内。现在,有些东西在全局范围内,但 不是全局对象的 属性。

有关此问题的更多详细信息,请参阅 Variables and Scoping in ES 6, section 6: The Global object。我们也可以在浏览器的控制台中进行如下实验(或者在 Node.js 中将 window 替换为 global):

class MyRect2 {
    constructor(height, width) {
        this.height = height;
        this.width = width;
    }

    area() {
      return this.height * this.width
    }
}

new window.MyRect2(2, 2)

结果:

TypeError: window.MyRect2 is not a constructor [Learn More]

但是

function MyRect3(height,width) {
    this.height = height;
    this.width = width;
    this.area = function() {return this.height * this.width;};
}
new window.MyRect3(2, 2)

给出:

Object { height: 2, width: 2, area: MyRect3/this.area() }

这与 Scala.js 目前的设计方式不一致。按照设计,Scala.js 只允许您访问全局 对象 ,而不是全局范围。这样做是为了让编译器永远不会影响您通过其内部生成的名称访问全局变量。也就是说,这是一个好主意,前提是您可以通过全局范围访问的所有内容也可以通过全局对象访问。

现在这个前提被打破了,这意味着 Scala.js 有一个严重的限制,我们需要修复它。

解决方法是将以下内容添加到您的 .js 文件中:

class MyRect2 { ... }
window.MyRect2 = MyRect2;

强制MyRect2成为全局对象的属性,因此让Scala.js访问它。