如何在JavaScript应用中使用Scala.js导出的BigDecimal?
Scala BigDecimal导出到JavaScript后的处理问题
我用Scala写了下面这个导出到JS的对象:
@JSExportTopLevel("Calculator") object Calculator { @JSExport def calculate(): BigDecimal = 3.14 }
在JavaScript里能正常调用,但返回的BigDecimal处理起来很麻烦:
let result = Calculator.calculate() assert(result == 123); // 能通过 assert(result === 123); // 失败 assert(result + 1 == 124); // 失败,实际结果是"1241"
浏览器控制台里这个返回值长这样:
Object { s_math_BigDecimal__f_bigDecimal: {…}, s_math_BigDecimal__f_mc: {…}, s_math_BigDecimal__f_computedHashCode: 1565550863 } s_math_BigDecimal__f_bigDecimal: Object { Ljava_math_BigDecimal__f__hashCode: 0, "Ljava_math_BigDecimal__f_java$math$BigDecimal$$_bitLength": 9, "Ljava_math_BigDecimal__f_java$math$BigDecimal$$_scale": 2, … } s_math_BigDecimal__f_computedHashCode: 1565550863 s_math_BigDecimal__f_mc: Object { Ljava_math_MathContext__f_precision: 34, Ljava_math_MathContext__f_roundingMode: {…} } <prototype>: Object { constructor: $c_s_math_BigDecimal(bigDecimal, mc), hashCode__I: hashCode__I(), equals__O__Z: equals__O__Z(that), … } "$classData": Object { constr: undefined, arrayDepth: 0, arrayEncodedName: "Lscala.math.BigDecimal;", … } "$div__s_math_BigDecimal__s_math_BigDecimal": function $div__s_math_BigDecimal__s_math_BigDecimal(that) "$minus__s_math_BigDecimal__s_math_BigDecimal": function $minus__s_math_BigDecimal__s_math_BigDecimal(that) "$plus__s_math_BigDecimal__s_math_BigDecimal": function $plus__s_math_BigDecimal__s_math_BigDecimal(that) "$times__s_math_BigDecimal__s_math_BigDecimal": function $times__s_math_BigDecimal__s_math_BigDecimal(that) byteValue__B: function byteValue__B() compare__O__I: function compare__O__I(that) constructor: function $c_s_math_BigDecimal(bigDecimal, mc) doubleValue__D: function doubleValue__D() equals__O__Z: function equals__O__Z(that) equals__s_math_BigDecimal__Z: function equals__s_math_BigDecimal__Z(that) floatValue__F: function floatValue__F() hashCode__I: function hashCode__I() intValue__I: function intValue__I() isDecimalDouble__Z: function isDecimalDouble__Z() isValidByte__Z: function isValidByte__Z() isValidChar__Z: function isValidChar__Z() isValidInt__Z: function isValidInt__Z() isValidLong__Z: function isValidLong__Z() isValidShort__Z: function isValidShort__Z() isWhole__Z: function isWhole__Z() longValue__J: function longValue__J() remainder__s_math_BigDecimal__s_math_BigDecimal: function remainder__s_math_BigDecimal__s_math_BigDecimal(that) shortValue__S: function shortValue__S() toBigIntExact__s_Option: function toBigIntExact__s_Option() toBigInt__s_math_BigInt: function toBigInt__s_math_BigInt() toString__T: function toString__T() <prototype>: Object { constructor: $c_s_math_ScalaNumber() }
想问下怎么正确用这个返回值?要不要导出其他类型?或者有别的解决办法?
解决方案
方法1:直接调用Scala BigDecimal暴露的转换方法
从控制台输出能看到,导出的对象自带了很多转换方法,直接调用即可:
- 转字符串:
result.toString__T() - 转Number类型:
- 转double:
result.doubleValue__D() - 转int:
result.intValue__I()(注意数值超出int范围会被截断) - 转long:
result.longValue__J()
- 转double:
JS代码修改示例:
let result = Calculator.calculate() let num = result.doubleValue__D() assert(num === 3.14); // 通过 assert(num + 1 === 4.14); // 通过
方法2:在Scala层提前转换为JS兼容类型
如果不想在JS里处理Scala对象,直接在Scala方法里返回JS原生支持的类型:
- 返回
Double:适合精度要求不高的场景 - 返回
String:适合需要保留精确小数的场景 - 返回
js.Number(需引入Scala.js的JS类型)
修改后的Scala代码:
import scala.scalajs.js import scala.scalajs.js.annotation._ @JSExportTopLevel("Calculator") object Calculator { // 返回Double类型 @JSExport def calculateAsDouble(): Double = 3.14 // 返回精确字符串 @JSExport def calculateAsString(): String = BigDecimal(3.14).toString // 返回JS原生Number @JSExport def calculateAsJSNumber(): js.Number = BigDecimal(3.14).doubleValue() }
JS调用示例:
let doubleResult = Calculator.calculateAsDouble() assert(doubleResult + 1 === 4.14); // 通过 let stringResult = Calculator.calculateAsString() assert(parseFloat(stringResult) + 1 === 4.14); // 通过
方法3:封装计算逻辑到Scala层
如果需要做精确计算,别把BigDecimal暴露给JS,而是在Scala里封装好所有计算操作,导出对应的方法:
@JSExportTopLevel("Calculator") object Calculator { private val value: BigDecimal = 3.14 @JSExport def getValue(): String = value.toString @JSExport def add(num: Double): String = (value + BigDecimal(num)).toString @JSExport def multiply(num: Double): String = (value * BigDecimal(num)).toString }
JS调用示例:
let sum = Calculator.add(1) assert(sum === "4.14"); // 通过
内容的提问来源于stack exchange,提问作者Big McLargeHuge
相关产品推荐
相关产品推荐

