scalajs作用域中的object和js中的*same* object有什么区别?全球范围

What's the difference between object in scalajs scope and *same* object in js.global scope?

本文关键字:object 区别 什么 范围 same 作用域 js scalajs 中的      更新时间:2023-09-26

我想写一个简单的例子来渲染立方体与THREEJS库。

package three
import org.scalajs.dom
import scala.scalajs.js
import scala.scalajs.js.Dynamic._
import scala.scalajs.js.annotation.JSName
object THREE extends js.Object
{
  @JSName ("THREE.Scene")
  class Scene extends js.Object
  {
       def add(obj: js.Object) = ???
  }
  @JSName ("THREE.Vector3")
  class Vector3(var x:js.Number, var y:js.Number, var z:js.Number) extends js.Object
  @JSName ("THREE.PerspectiveCamera")
  class PerspectiveCamera(a:js.Number,b:js.Number,c:js.Number,d:js.Number) extends js.Object
  {
    var position:Vector3 = _
  }
  @JSName ("THREE.WebGLRenderer")
  class WebGLRenderer(params:js.Dynamic) extends js.Object
  {
    def render(scene:js.Object, camera:js.Object) = ???
  }
  @JSName ("THREE.WebGLRenderer")
  class SimpleWebGLRenderer() extends js.Object
  {
    def render(scene:js.Object, camera:js.Object) = ???
    var domElement : js.Dynamic = _
  }
  @JSName ("THREE.BoxGeometry")
  class BoxGeometry(a:js.Number,b:js.Number,c:js.Number) extends js.Object
  @JSName ("THREE.MeshBasicMaterial")
  class MeshBasicMaterial(params:js.Dynamic) extends js.Object
  @JSName ("THREE.MeshBasicMaterial")
  class SimpleMeshBasicMaterial() extends js.Object
  @JSName ("THREE.Mesh")
  class Mesh(geometry:js.Object, material:js.Object) extends js.Object
}

object ThreeExample
{
  def render() =
  {
    val scene = new THREE.Scene()
    val camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
    val renderer = new THREE.WebGLRenderer(js.Dynamic.literal(
      canvas = global.document.getElementById("ThreeCanvas")
    ));
    val geometry = new THREE.BoxGeometry(1,1,1);
    val material = new THREE.SimpleMeshBasicMaterial()
    camera.position.z = 2;
    val cube = new THREE.Mesh(geometry, material);

现在是有趣的部分。如果我想写

scene.add(cube);
renderer.render(scene, camera);

ScalaJS.c。jl_ClassCastException {s$1: "[object object]不是scala.runtime.Nothing$", e$1: null, stackTrace$1: null, stackdata: TypeError, constructor: function…}

错误。而如果我尝试

global._scene = scene
global._cube = cube
global._camera = camera
global._renderer = renderer
global._scene.add(global._cube)
global._renderer.render(global._scene, global._camera);

一切都正确呈现,没有错误。我是说,有什么陷阱吗?这两者之间有什么区别吗?_scene和scene或global._scene。添加和场景。div添加?

详细说明一下我的评论:基本上没有区别。静态类型接口只是与动态类型接口使用的相同机制的类型化外观。但是,因为它是静态的,所以它会对调用的方法返回的值进行检查。

在你的例子中,当调用renderer.render()时,编译器增加了一个检查,该JavaScript方法返回的值实际上符合WebGLRenderer.render()的静态结果类型。但是这个结果类型是什么呢?是Nothing !为什么呢?因为该方法的主体是???,类型是Nothing,所以scalac推断该方法的结果类型为Nothing。然后检查失败,因为render从JavaScript返回的值不是Nothing类型(显然,因为没有值具有该类型),这导致ClassCastException .

你想要的显然不是Nothing,而是Unit。所以你所要做的就是用: Unit显式地显示这个结果类型,像这样:

def render(scene:js.Object, camera:js.Object): Unit = ???

一般来说,您应该总是显式地指定facade类型中方法的结果类型,因为否则它们将被推断为Nothing,这不是您想要的。