
本文讲解如何避免因共享对象属性名导致的 JSON 序列化异常,重点解决多函数共用同一数据对象时因重复赋值同名属性(如 Models)引发的类型不一致问题。
本文讲解如何避免因共享对象属性名导致的 json 序列化异常,重点解决多函数共用同一数据对象时因重复赋值同名属性(如 `models`)引发的类型不一致问题。
在 JavaScript 前端开发中,尤其是使用 Kendo UI 等富组件库时,常需从当前 Grid 获取数据项(如 currentGrid.dataItem(row)),再附加业务字段后传递给新页面。表面上看,X() 和 Y() 是两个独立函数,各自操作局部变量 rawData,但关键陷阱在于:rawData 并非深拷贝对象,而是对原始数据模型的直接引用。当 X() 设置 rawData.Models = "some text"(字符串),而 Y() 后续又设置 rawData.Models = ["some text"](数组)时,该属性在内存中被反复覆盖——若 X() 再次执行,其期望的字符串类型可能已被 Y() 改为数组,导致后端 Newtonsoft.Json 解析失败(Unexpected character encountered while parsing value)。
这并非“全局变量缓存”问题,而是对象引用污染(Object Reference Pollution):多个函数无意间复用并修改了同一个底层数据对象的属性。因此,解决方案的核心不是“重置全局变量”,而是确保数据传递的隔离性与类型契约一致性。
✅ 推荐实践:始终创建干净的数据副本
使用 Object.assign({}) 或展开运算符生成浅拷贝,避免污染原始数据:
function X() {
"use strict";
const tab = globalFunctionToGetActiveTab();
const view = globalFunctionToGetView(tab.id);
const tabPane = tab.getPane();
const currentGrid = tabPane.find(".k-grid:visible").data("kendoGrid");
const row = $(e).closest("tr");
const rawData = currentGrid.dataItem(row);
// 创建独立副本,仅添加本函数所需字段
const payload = { ...rawData, Models: "some text" };
OpenPageA(payload);
}
function Y() {
"use strict";
const tab = globalFunctionToGetActiveTab();
const view = globalFunctionToGetView(tab.id);
const tabPane = tab.getPane();
const currentGrid = tabPane.find(".k-grid:visible").data("kendoGrid");
const row = $(e).closest("tr");
const rawData = currentGrid.dataItem(row);
// 使用不同字段名 + 独立副本,双重保障
const payload = { ...rawData, ModelList: ["some text"] };
OpenPageB(payload);
}⚠️ 注意事项与进阶建议
-
避免直接修改
dataItem返回的对象:Kendo Grid 的dataItem()返回的是 Observable 对象或原始数据引用,修改它会影响 Grid 渲染及后续逻辑。 -
深拷贝场景:若
rawData包含嵌套对象且需完全隔离,使用JSON.parse(JSON.stringify(rawData))(注意不可序列化值限制)或 Lodash 的_.cloneDeep()。 -
类型契约前置:在 API 设计阶段明确每个接口对
Models字段的类型要求(如统一为数组),前端通过Array.isArray()校验或标准化处理:// 统一转为数组,兼容单值/多值场景 const models = Array.isArray(rawData.Models) ? rawData.Models : rawData.Models ? [rawData.Models] : []; const payload = { ...rawData, Models: models }; -
不依赖重命名治标:虽然将
Models改为ModelList可规避冲突,但本质是掩盖设计缺陷;更健壮的方式是保证每次传输的数据结构自治、无副作用。
总结:JavaScript 中没有真正的“全局函数变量缓存”需要手动重置;真正需要管理的是对象引用的生命周期与作用域边界。通过默认采用不可变数据模式(immutable-by-default)、显式克隆、语义化字段命名与类型校验,可从根本上杜绝此类跨函数数据污染问题。
立即学习“Java免费学习笔记(深入)”;


















