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

为何instanceof在JSON.stringify()中表现异常?decimal.js场景

解决JSON.stringify replacer中Decimal实例检测不一致的问题

你碰到的这个问题其实挺常见的,核心原因在于decimal.js的实例自带了toJSON()方法,而JSON.stringify在序列化过程中会优先调用对象的toJSON()方法——这就导致你的replacer函数拿到的value参数,已经不是原始的Decimal实例了,而是toJSON()返回的转换后的值(默认是字符串格式的数值)。而函数外直接检测myObj.myNum时,你拿到的是未被转换的原始实例,所以两次instanceof的结果才会不一样。

下面给你两种可行的解决方案:

方案1:通过this获取原始实例(推荐)

在replacer函数里(注意要用普通函数,别用箭头函数,不然this会绑定到外层作用域),this指向当前正在被序列化的对象,你可以直接从this里拿到未被转换的原始属性值,再做类型检测:

const Decimal = require('decimal.js');

const myObj = { myNum: new Decimal(0.3) };

console.log('Property "myNum" is a Decimal:', myObj.myNum instanceof Decimal); // 输出 true

const replacer = function(key, value) {
  // 从当前对象拿到原始值,而不是用JSON转换后的value
  const originalValue = this[key];
  if (originalValue instanceof Decimal) {
    // 这里自定义你的序列化逻辑,比如转成字符串或者结构化对象
    return originalValue.toString();
    // 或者返回带类型标识的对象,方便后续反序列化:
    // return { __type: 'Decimal', value: originalValue.toString() };
  }
  return value;
};

const jsonStr = JSON.stringify(myObj, replacer);
console.log(jsonStr); // 输出 {"myNum":"0.3"}

方案2:禁用Decimal的toJSON方法

如果你不想让JSON.stringify自动转换Decimal实例,可以直接覆盖掉它的toJSON方法,这样replacer里拿到的value就是原始的Decimal实例了:

const Decimal = require('decimal.js');

// 禁用toJSON方法,让JSON.stringify保留原始实例
Decimal.prototype.toJSON = undefined;

const myObj = { myNum: new Decimal(0.3) };

console.log('Property "myNum" is a Decimal:', myObj.myNum instanceof Decimal); // 输出 true

const replacer = (key, value) => {
  if (value instanceof Decimal) {
    return value.toString();
  }
  return value;
};

const jsonStr = JSON.stringify(myObj, replacer);
console.log(jsonStr); // 输出 {"myNum":"0.3"}

补充说明

ECMAScript的规范里明确规定:JSON.stringify在处理每个值时,会先检查该值是否有toJSON()方法,如果有,就调用这个方法并使用返回的结果来进行后续的序列化流程。decimal.js为了方便默认实现了这个方法,这就是导致你检测结果不一致的根本原因。

内容的提问来源于stack exchange,提问作者Nathan Friend

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:58:44