Edited at

Scala traitとnative JS traitとnon-naitive JS trait

native JS typeとnon-native JS typeという概念がある。

それぞれのtypeのtraitが存在し、そもそものScalaのtraitに加えて、


  • scala trait (勝手に呼んでいる)

  • native JS trait

  • non-native JS trait

の三種類が存在する。


native JS trait

native JSはJavaScriptで実装されたライブラリを読み込んで使う場合に使う。

いくら書いてもJavaScriptコードは生成されない。

Scala.js上でインスタンスをつくるにはjs.Dynamic.literalを使用する。

facadeを書くのに使う。

@js.native

trait Point extends js.Object {
val x: Int
val y: Int
}

val point = js.Dynamic.literal(x = 1, y = 2).asInstanceOf[Point]
js.Dynamic.global.console.log(p) // => {x: 1, y: 2}

js.Anyの派生をミックスインしていて、@js.nativeが付与されてるのがポイント。

より詳細はこちらに。

https://www.scala-js.org/doc/interoperability/facade-types.html


non-native JS trait

Scala.jsで実装したJSのコード。

classにミックスインしたり、無名クラスでインスタンスが作れる。

JavaScriptのオブジェクトとして利用可能

メソッドは定義できない。

trait Point extends js.Object {

val x: Int
val y: Int
}
val point = new Point {
override val x: Int = 1
override val y: Int = 2
}
js.Dynamic.global.console.log(point) // => { x: 1, x: 2}

利用には、

@ScalaJSDefinedアノテーションをつけるか、sbtに以下のコードを貼り付ける必要がある。

scalacOptions += "-P:scalajs:sjsDefinedByDefault"

native JSに比較して、安全にインスタンスが作成できる。

より詳細はこちらに。

https://www.scala-js.org/doc/interoperability/sjs-defined-js-classes.html


Scala trait

普通のScalaのトレイト

何らかのコードが生成される。

普通に使える。

定義したフィールドがプロパティと一致しないため、JavaScriptのオブジェクトとしては使えない。


trait Point {
val x: Int
val y: Int
}
val point = new Point {
override x: Int = 1
override y: Int = 2
}
js.Dynamic.global.console.log(p.asInstanceOf[js.Any]) // => $c_LPointScala { 'x$1': 1, 'y$1': 2 }
println(p.x) // => 1

プロパティはフィールド名と一致しない。

代わりにgetterが定義されてるのを確認できる。

JSのライブラリに渡して安全に動くとは限らない。


まとめ

native JS
non-native JS
Scala

インスタンス作成
js.Dynamic.literalで
できる
できる

メソッド定義
インターフェースのみ実装は生成されない
できない(抽象クラスでできる)
できる

js Objectとして使用
できる
できる
できるがおすすめできない