Js.cast() 如何进行类型检查?

ᴇʟᴇ*_*ᴀтᴇ 2 gwt gwt-elemental gwt-jsinterop

我正在使用带有 elemental2-1.0.0-RC1 的 GWT 2.9。

以下代码ClassCastException在运行时抛出 a :

DocumentRange documentRange = Js.cast(DomGlobal.document); // Fails
Range range = documentRange.createRange(); // Never reaches here
Run Code Online (Sandbox Code Playgroud)

当我改为使用 an 时Js.uncheckedCast(),它成功了:

DocumentRange documentRange = Js.uncheckedCast(DomGlobal.document);
Range range = documentRange.createRange(); // Works
Run Code Online (Sandbox Code Playgroud)

的文档Js.uncheckedCast()说:

“你应该总是更喜欢定期投射(除非你知道自己在做什么!)。”

我不知道为什么我必须使用它,所以我感到紧张。有人可以解释如何Js.cast()执行其类型检查以及为什么我需要Js.uncheckedCast()在这种情况下使用 an吗?

Col*_*rth 5

Js.cast()是一种作弊的方法,可以做一些 Java 语言不允许但实际上可能是合法的事情。忽略“它实际上是如何工作的”,这个想法是你现在可以解决 Java 会抱怨的问题,即使结果是合法的。

一个示例可能是您使用java.lang.Doubleordouble并希望将其视为 aJsNumber以便您可以对其调用 toPrecision(2) 。由于java.lang.Double是 final,因此强制转换为不相关的类型是不合法的,但 Java 不知道在 GWT 中, Double 实际上只是一个 js Number。因此,您可以使用Js.cast(). 编译器将在其中插入运行时类型检查,在运行时验证您的号码实际上是一个 JS Number 实例。

另一个示例可能是尝试扩展 elemental2 提供的一些本机类型,以实现缺失功能的解决方法,或执行特定于浏览器的操作。您的新类可能不会扩展现有类 - 从 JS 的角度来看,这没关系,您只是在描述您知道将在运行时存在的 API。因此,我们需要避免 Java 语言检查“这个转换是否有意义?”,而只是告诉编译器尝试它。

另一方面,您可以使用Js.uncheckedCast(). 这用于您甚至要求运行时跳过检查并假装它会工作的情况。这可以让你做一些奇怪的事情,比如将字符串视为数组,或者解决跨框架问题。不会发出运行时检查,因此如果缺少方法/属性,您可能只会得到 TypeError,而不是正确的 ClassCastException。


在 elemental2-dom 1.0.0-RC1 中,有一个名为 的类DocumentRange,但它没有任何意义——它被声明为一个类,这意味着它可以在 JS 中进行类型检查,但浏览器规范说它应该是一个“接口”(在 JS 领域意味着它只是一种类型的描述,而不是你可以进行类型检查的东西)。https://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level2-DocumentRange-method-createRange

这个错误是从closure-compiler继承的,它声称它有一个构造函数:https : //github.com/google/closure-compiler/blob/6a418aa/externs/browser/w3c_range.js#L241-L251

修复是为了让闭包编译器将其称为接口,并发布 elemental2 的新版本,以便您可以使用它。


您可以在此处进行两种解决方法。第一种是欺骗Js.uncheckedCast(DomGlobal.document)并说“是的,我知道Document不是instanceof DocumentRange,但那是因为没有这样的类DocumentRange,所以假装它有效,这样我就可以调用createRange()它”。这就是您已经在做的事情 - 它隐藏了存在错误的事实,但最终它会起作用。

“正确”的答案是声明你自己的DocumentRange,然后做 aJs.cast()来代替。这仍然很糟糕——你必须保留你的新界面,直到关闭被修复,然后 elemental2 被释放,然后你必须记住清理它。

在这种情况下,我建议向 GWT 撒谎并使用Js.uncheckedCast()- 这里只有一种方法,并且不太可能以有意义的方式改变。