Scala.js 本机 Javascript 构造函数

Scala.js native Javascript constructors

Scala.js 原生 JS 类型的外观可能如下所示(来自 Three.js facade):

@js.native
@JSName("THREE.Vector3")
class Vector3 extends Vector {
  def this(x: Double = js.native, y: Double = js.native, z: Double = js.native) = this()
  var x: Double = js.native
  var y: Double = js.native
  var z: Double = js.native

/* ... */
}

构造Vector3的函数对应的Javascript definition为:

function Vector3( x, y, z ) {

    this.x = x || 0;
    this.y = y || 0;
    this.z = z || 0;

}

我已经阅读了有关 creating Scala.js facades 的文档,但是那里只是简要地提到了构造函数。 Facade 中的代码在实际代码中工作正常,但是我不确定定义是否正确以及为什么以及如何工作。

Esp。第二点让我感到困惑。这怎么行?在这三种情况下,我想知道为构造函数生成了哪些 JS 代码以及为什么。

人们还可以想象一种不同的方式来编写门面。这样会更正确吗?

class Vector3(var x: Double = js.native, var y: Double = js.native, var z: Double = js.native) extends Vector {

/* ... */
}

定义正确。 JavaScript 构造函数的门面规则非常简单地说明:当遇到诸如

的调用时
new C(arg1, ..., argN)

C是一个JavaScriptclass,这转化为

new Cconstr(arg1, ..., argN)

其中 Cconstr 是计算 js.constructorOf[C] 的结果。对于本机 JavaScript class,js.constructorOf[C] 在全局范围内查找 C 的名称(或应用 @JSName@JSImport 规则)。具体来说,在您的示例中,调用

new Vector3(3, 4, 5)

转换为

new <global>.THREE.Vector3(3, 4, 5)

请特别注意,构造函数定义的 body 完全无关,因为调用站点直接调用 Three.js 中的 JavaScript 代码图书馆。因此,语义规则完全忽略了 3-arg 构造函数调用 0-arg 构造函数并忽略其参数的事实。该调用对于遵守 Scala 的类型检查规则是必要的,但在语义上无关紧要。

同样,默认参数值的实际值在语义上是无关的。它们的存在使参数成为可选参数,但编译器会忽略它们的值。调用如

new Vector3(3)

翻译成JavaScript到

new <global>.THREE.Vector3(3)

其中 yz 参数完全没有给出,留给 JavaScript 来决定如何处理它们。

最后,您的替代定义:

class Vector3(var x: Double = js.native, var y: Double = js.native, var z: Double = js.native)

同样有效。它没有明确的 0-arg 构造函数,但它也可以是 "accessed" 通过给构造函数 0 个参数,它有 3 个可选参数。不过,这个定义当然更简洁,看起来更 Scala-esque,所以我个人会这样定义。但它并不比最初的更正确