漏洞? JsNumber toFixed returns SuperDev 和 JS 中的不同值
Bug? JsNumber toFixed returns different values in SuperDev and JS
我正在使用 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 上尝试了 运行ning 代码。他们都表现出相同的行为。
知道为什么会有差异吗?我能做些什么吗?
更新: 仔细研究后,我发现这与整数参数的强制转换有关。
console.log(num.toFixed(3)); // 123 (wrong)
console.log(num.toFixed(3d)); // 123.456 (correct)
似乎Elemental2中的JsNumber
class定义了签名为:
public native String toFixed(Object digits);
我觉得应该是:
public native String toFixed(int digits);
我仍然不确定为什么它在 SuperDev 模式下有效,但在编译时却无效。
问题是 "java" 自动将 int
包装为 Integer 并且 GWT 最终将装箱的 Integer 转换为 JS 中的特殊对象(不是数字)。但是,如果您使用双精度数,则装箱的双精度数也会被 GWT 转译为本机数字,问题就会消失。
我不太确定为什么这在超级开发模式下有效,但它不应该。我认为区别在于 SDM 将本机 toString 映射到 Java toString,并且(甚至更奇怪)本机 toFixed 调用参数的 toString。在 SDM 中,boxed-interger#toString returns 数字的字符串表示最终强制返回 int,但在生产中,boxed-interger#toString returns “[object Object]”,它处理为 NaN。
有一个特殊的注释 @DoNotAutobox
可以在 JS 本机 API 中使用原始整数。这可以防止整数自动换行,因此 int 会转换为本机数字(Js#coerceToInt 方法中的示例用法)。 Elemental2 可能会按照您的建议添加此注释或将类型更改为 int。请在 elemental2 存储库中创建一个问题来解决此问题 (https://github.com/google/elemental2/issues/new)。
抓得好!这似乎是在生成 Elemental2 的源代码时使用的 jsinterop-generator 配置中的错误。由于 JS 没有办法说一个数字是整数还是浮点值,因此 jsinterop-generator 使用的源 material 无法准确描述该参数需要是什么。
通常,修复方法是将此添加到整数-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.5 and https://www.ecma-international.org/ecma-262/5.1/#sec-9.3)。
因此,我们需要确保将 Java 开发人员提供给函数的任何文字值传递给函数,以便在 JS 中正确解析它 - 这意味着参数需要注释@DoNotAutobox
。或者,我们可以澄清这一点,说它可以是 Object 或 Number 作为参数,并且 toFixed(Object) 仍然会被发出,但现在也会有一个数字版本。
或者,您可以像以前那样解决这个问题,或者提供一个包含您想要的位数的字符串值:
console.log(num.toFixed("3"));
我正在使用 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 上尝试了 运行ning 代码。他们都表现出相同的行为。
知道为什么会有差异吗?我能做些什么吗?
更新: 仔细研究后,我发现这与整数参数的强制转换有关。
console.log(num.toFixed(3)); // 123 (wrong)
console.log(num.toFixed(3d)); // 123.456 (correct)
似乎Elemental2中的JsNumber
class定义了签名为:
public native String toFixed(Object digits);
我觉得应该是:
public native String toFixed(int digits);
我仍然不确定为什么它在 SuperDev 模式下有效,但在编译时却无效。
问题是 "java" 自动将 int
包装为 Integer 并且 GWT 最终将装箱的 Integer 转换为 JS 中的特殊对象(不是数字)。但是,如果您使用双精度数,则装箱的双精度数也会被 GWT 转译为本机数字,问题就会消失。
我不太确定为什么这在超级开发模式下有效,但它不应该。我认为区别在于 SDM 将本机 toString 映射到 Java toString,并且(甚至更奇怪)本机 toFixed 调用参数的 toString。在 SDM 中,boxed-interger#toString returns 数字的字符串表示最终强制返回 int,但在生产中,boxed-interger#toString returns “[object Object]”,它处理为 NaN。
有一个特殊的注释 @DoNotAutobox
可以在 JS 本机 API 中使用原始整数。这可以防止整数自动换行,因此 int 会转换为本机数字(Js#coerceToInt 方法中的示例用法)。 Elemental2 可能会按照您的建议添加此注释或将类型更改为 int。请在 elemental2 存储库中创建一个问题来解决此问题 (https://github.com/google/elemental2/issues/new)。
抓得好!这似乎是在生成 Elemental2 的源代码时使用的 jsinterop-generator 配置中的错误。由于 JS 没有办法说一个数字是整数还是浮点值,因此 jsinterop-generator 使用的源 material 无法准确描述该参数需要是什么。
通常,修复方法是将此添加到整数-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.5 and https://www.ecma-international.org/ecma-262/5.1/#sec-9.3)。
因此,我们需要确保将 Java 开发人员提供给函数的任何文字值传递给函数,以便在 JS 中正确解析它 - 这意味着参数需要注释@DoNotAutobox
。或者,我们可以澄清这一点,说它可以是 Object 或 Number 作为参数,并且 toFixed(Object) 仍然会被发出,但现在也会有一个数字版本。
或者,您可以像以前那样解决这个问题,或者提供一个包含您想要的位数的字符串值:
console.log(num.toFixed("3"));