You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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()

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 03:09:26