0

我正在使用 GWT 2.8.2。

当我在 SuperDev 模式下运行以下代码时,它会记录123.456,这是我所期望的。

double d = 123.456789;
JsNumber num = Js.cast(d);
console.log(num.toFixed(3));

当我编译成 JavaScript 并运行时,它会记录123(即它不显示小数位)。

我尝试在 Android Chrome、Windows Chrome 和 Windows Firefox 上运行代码。它们都表现出相同的行为。

知道为什么会有差异,我能做些什么吗?


更新:经过一番挖掘,我发现这与整数参数的强制有关。

console.log(num.toFixed(3));  // 123 (wrong)
console.log(num.toFixed(3d)); // 123.456 (correct)

似乎JsNumberElemental2 中的类已将签名定义为:

public native String toFixed(Object digits);

我认为应该是:

public native String toFixed(int digits);

我仍然不确定为什么它在 SuperDev 模式下工作而不是在编译时工作。

4

2 回答 2

1

不错的收获!这似乎是生成 Elemental2 源时使用的 jsinterop-generator 配置中的一个错误。由于 JS 没有办法说数字是整数还是浮点值,所以 jsinterop-generator 使用的源材料无法准确地描述该参数需要是什么。

通常,修复方法是将其添加到 integer-entities.txt ( https://github.com/google/elemental2/blob/master/java/elemental2/core/integer_entities.txt ),以便生成器知道这参数只能是整数。但是,当我进行此更改时,生成器并未对新行进行操作,并记录了这一事实。事实证明,只有当参数是某种数字时,它才会进行这种更改,而这Object显然不是。

正确的修复也可能是修复用于描述“JsNumber.toFixed”应该作为参数的外部变量。规范说这实际上可以采用一些非数字值,并且在转换为数字后,甚至不需要是整数(参见https://www.ecma-international.org/ecma-262/5.1/# sec-15.7.4.5https://www.ecma-international.org/ecma-262/5.1/#sec-9.3)。

因此,相反,我们需要确保将 Java 开发人员提供的任何文字值传递给函数,以便在 JS 中正确解析它 - 这意味着参数需要使用@DoNotAutobox. 或者,我们可以澄清这一点,说它可以是 Object 或 Number 作为参数,并且仍然会发出 toFixed(Object),但现在也会有一个数字版本。


或者,您可以像以前一样解决此问题,或者提供所需位数的字符串值:

console.log(num.toFixed("3"));

归档为https://github.com/google/elemental2/issues/129

于 2019-07-31T17:06:43.907 回答
1

问题是“java”自动将 包装int为 Integer 并且 GWT 最终将装箱的 Integer 转换为 JS 中的特殊对象(不是数字)。但是,如果您使用双精度数,则盒装双精度数也会被 GWT 转译为本机数字,问题就消失了。

我不确定为什么这在超级开发模式下有效,但它不应该。我认为不同之处在于 SDM 将本机 toString 映射到 Java toString,并且(甚至更奇怪)本机 toFixed 调用参数的 toString。在 SDM 中,boxed-interger#toString 返回数字的字符串表示形式,该数字最终强制返回为 int,但在生产中,boxed-interger#toString 返回“[object Object]”,它被处理为 NaN。

有一个特殊的注释@DoNotAutobox可以在 JS 原生 API 中使用原始整数。这可以防止整数自动换行,因此 int 被转换为本机数字(Js#coerceToInt 方法中的示例用法)。Elemental2 可能会按照您的建议添加此注释或将类型更改为 int。请在 elemental2 存储库中创建一个问题来解决此问题(https://github.com/google/elemental2/issues/new)。

于 2019-07-31T10:09:31.003 回答