链式 JS 调用和这个 scala.js

Chained JS calls and this in scala.js

我刚刚开始使用 Scala.js 并尝试让一个简单的 d3.js 语句起作用:

d3.select("body").append("svg")

为了获得最小的工作版本,我克隆了 scala.js 教程,将 d3.js 添加到索引 - fastopt.html 并在 ScalaJSExample.scala (借自 https://github.com/spaced/scala-js-d3):

trait Selection extends js.Array[js.Any] {
  var append: js.Function1[String, Selection] = js.native
}

trait Base extends js.Object {
  def select(selector: String): Selection = js.native
}

object Global extends scalajs.js.GlobalScope {
  val d3: Base = js.native
}

object ScalaJSExample extends js.JSApp {
  import Global._
  def main(): Unit = { 
    d3.select("body").append("svg")
  }

}

但是此代码失败并出现错误:

Uncaught TypeError: this.select is not a function
   _a.append @ d3.v3.min.js:3

语句的 fastOpt 版本是:

 (0, $g["d3"]["select"]("body")["append"])("svg")

对我来说,看起来 append 是用一个 this 调用的,它不是选择,因此追加内的调用失败。

以下版本的代码可以工作,但是非常麻烦并且不是 d3 惯用的,因为 d3 很大程度上依赖于方法链:

trait Selection extends js.Array[js.Any] {
  var append: js.ThisFunction1[Selection, String, Selection] = js.native
}

trait Base extends js.Object {
  def select(selector: String): Selection = js.native
}

object Global extends scalajs.js.GlobalScope {
  val d3: Base = js.native
}

object ScalaJSExample extends js.JSApp {
  import Global._
  def main(): Unit = { 
    val sel = d3.select("body")
    sel.append(sel, "svg")
}

有没有更好的方法将选择作为 this 传递给附加,这让我可以保留 d3 的流畅界面风格?

原来的门面类型是错误的,这就是你遇到麻烦的原因。 append的定义应该是def,而不是函数类型的var

trait Selection extends js.Array[js.Any] {
  def append(param: String): Selection = js.native
}

然后您的链式调用将工作并生成适当的 JS。