问题
While trying to write scalajs facade for javascript class, i am getting the following error: "error Uncaught TypeError: $g.MyRect2 is not a constructor" in chrome console.
My javascript class defination is as follows:
class MyRect2 {
constructor(height, width) {
this.height = height;
this.width = width;
}
area() {
return this.height * this.width
}
}
Then I imported it as follows in 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
}
Finally I instantiated the class as follows
val rect2 = new MyRect2(2,2) //This is giving the above error.
However, when I write javascript class as below, the same import and instantiation works
function MyRect2(height,width) {
this.height = height;
this.width = width;
this.area = function() {return this.height * this.width;};
}
Pls suggest what i am not doing right.
回答1:
Edit: This has been fixed in Scala.js 1.x (as of this writing, Scala.js 1.0.0-M1 has been released).
Ouch ... Well that just made my day a lot darker.
It turns out that class
declarations (along with let
s and const
s, but unlike var
s and functions
) do not add what they declare as properties of the global object of JavaScript. They are only available in the global scope.
Until ECMAScript 5.1, these two things were equivalent: something was in the global scope if and only if it was a property of the global object. Now, there are things that are in the global scope but are not properties of the global object.
See Variables and Scoping in ES 6, section 6: The Global object for more details on this issue. We can also experiment as follows in a browser's console (or in Node.js by replacing window
by global
):
class MyRect2 {
constructor(height, width) {
this.height = height;
this.width = width;
}
area() {
return this.height * this.width
}
}
new window.MyRect2(2, 2)
results in:
TypeError: window.MyRect2 is not a constructor [Learn More]
but
function MyRect3(height,width) {
this.height = height;
this.width = width;
this.area = function() {return this.height * this.width;};
}
new window.MyRect3(2, 2)
gives:
Object { height: 2, width: 2, area: MyRect3/this.area() }
This is at odds with how Scala.js was designed so far. By design, Scala.js only gives you access to the global object, and not the global scope. This was done so that the compiler would never shadow your accessing to a global variable by its own internally generated names. I.e., it was a good idea given the premise that everything you would access through the global scope can also be accessed through the global object.
Now this premise is broken, which means that Scala.js has a severe limitation, which we will need to fix.
The workaround is to add the following to your .js file:
class MyRect2 { ... }
window.MyRect2 = MyRect2;
to force MyRect2
to become a property of the global object, and therefore let Scala.js access it.
来源:https://stackoverflow.com/questions/42745118/scala-js-does-not-see-a-js-class-in-the-global-scope-but-sees-a-constructor-f