在尝试为javascript类编写scalajs facade时,我收到以下错误:" error Uncaught TypeError:$ g.MyRect2不是构造函数"在chrome控制台中。
我的javascript类定义如下:
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
}
最后,我将类实例化如下
val rect2 = new MyRect2(2,2) //This is giving the above error.
但是,当我编写如下的javascript类时,相同的导入和实例化工作
function MyRect2(height,width) {
this.height = height;
this.width = width;
this.area = function() {return this.height * this.width;};
}
请建议我做得不对。
答案 0 :(得分:4)
编辑:这已在Scala.js 1.x中修复(截至撰写本文时,Scala.js 1.0.0-M1已发布)。
哎哟......好吧,这让我的日子变得更黑了。事实证明class
声明(以及let
和const
s,但与var
和functions
不同)不添加他们声明为JavaScript的全局对象的属性。它们仅在全局范围中可用。
在ECMAScript 5.1之前,这两件事是等价的:当且仅当它是全局对象的属性时,某些东西才在全局范围内。现在,有些东西属于全局范围,但是不是全局对象的属性。
有关此问题的详细信息,请参阅Variables and Scoping in ES 6, section 6: The Global object。我们还可以在浏览器的控制台中进行如下实验(或通过window
替换global
来在Node.js中进行实验):
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访问它。