GraalVM中更新单个数组却同步修改另一数组的问题排查
在GraalVM中修改一个数组导致另一个数组同步变更的问题
在GraalVM环境下,我遇到一个异常问题:仅更新results数组时,originalResults数组也会同步被修改。我尝试过使用扩展运算符复制原数组、通过循环单独填充数组,但问题仍未解决。
相关代码
调用代码(code1)
s.print("sys_imported_saved_configuration_id: " + sys_imported_saved_configuration_id); const sys_imported_saved_configuration_data = new SysRecord({ sys_table_name: 'sys_imported_saved_configuration_data', where: [ [{ "sys_column": "sys_imported_saved_configuration_id", "sys_operator": "=", "sys_value": sys_imported_saved_configuration_id }] ], select_columns: ['sys_id', 'sys_data', 'sys_operation'] }); const is_data_available = await sys_imported_saved_configuration_data.query();
SysRecord类代码(code2)
class SysRecord { constructor({ sys_table_name, select_columns = null, where = null, where_sys_id = null, sort_column = null, sort_direction = null }) { this.sys_table_name = sys_table_name; this.select_columns = select_columns || []; this.where = where || {}; this.where_sys_id = where_sys_id; this.sort_column = sort_column; this.sort_direction = sort_direction; this.results = []; this.currentIndex = -1; this.originalResults = []; // 用于追踪原始记录 } toMap() { const queryParams = {}; if (this.sys_table_name) queryParams['sys_table_name'] = this.sys_table_name; if (this.select_columns.length > 0) queryParams['select_columns'] = JSON.stringify(this.select_columns); if (Object.keys(this.where).length > 0) queryParams['where'] = JSON.stringify(this.where); if (this.where_sys_id) queryParams['where_sys_id'] = this.where_sys_id; if (this.sort_column) queryParams['sort_column'] = this.sort_column; if (this.sort_direction) queryParams['sort_direction'] = this.sort_direction; return queryParams; } async query() { s.print("\n\nquery()"); // 检查并添加sys_id和sys_table_name到select_columns(如果不存在) if (!this.select_columns.includes('sys_id')) { this.select_columns.push('sys_id'); } if (!this.select_columns.includes('sys_table_name')) { this.select_columns.push('sys_table_name'); } // 执行查询 const records = await s.get(this.toMap()); s.print("RECORDS: " + records); for (var record of records) { s.print("record: " + record); this.originalResults.push(record); this.results.push(record); } // 曾尝试的方案(无效) // this.originalResults = [...records]; // this.results = [...records]; s.print("originalResults: " + this.originalResults); s.print("results: " + this.results); this.currentIndex = 0; this.set('sys_create', true); s.print("\noriginalResults2: " + this.originalResults); s.print("results2: " + this.results); return this.results.length > 0; } get(fieldName) { if (this.currentIndex >= 0 && this.currentIndex < this.results.length) { return this.results[this.currentIndex][fieldName]; } return null; } set(fieldName, value) { // s.print("set called with " + fieldName + " :: " + value + " at index = " + this.currentIndex); if (this.currentIndex >= 0 && this.currentIndex < this.results.length) { this.results[this.currentIndex][fieldName] = value; } } }
问题原因
这不是GraalVM的特殊问题,而是JavaScript对象引用的特性:
records数组中的元素是对象,无论是用push(record)还是扩展运算符[...records],都是浅拷贝——只复制了数组的结构,两个数组中的元素依然指向同一个对象引用。- 当你调用
set方法修改results数组中对象的属性时,实际上是修改了底层的对象本身,originalResults数组中对应的对象自然也会同步变化。
解决方案
需要对每个对象进行深拷贝,确保两个数组中的对象是完全独立的实例。可以根据对象的结构选择以下方式:
方案1:使用JSON序列化/反序列化(适用于无循环引用的对象)
修改query方法中的循环部分:
for (const record of records) { s.print("record: " + record); // 深拷贝单个对象 const originalCopy = JSON.parse(JSON.stringify(record)); const resultCopy = JSON.parse(JSON.stringify(record)); this.originalResults.push(originalCopy); this.results.push(resultCopy); }
方案2:手动拷贝对象属性(更安全,适用于已知结构的对象)
如果明确知道record的属性,可以手动复制避免序列化的潜在问题:
for (const record of records) { s.print("record: " + record); const recordCopy = { sys_id: record.sys_id, sys_data: record.sys_data, sys_operation: record.sys_operation, sys_table_name: record.sys_table_name }; this.originalResults.push({...recordCopy}); // 再浅拷贝一次确保独立 this.results.push(recordCopy); }
方案3:使用结构化克隆(现代环境支持)
如果运行环境支持,可以使用structuredCloneAPI进行深拷贝:
for (const record of records) { s.print("record: " + record); this.originalResults.push(structuredClone(record)); this.results.push(structuredClone(record)); }
内容的提问来源于stack exchange,提问作者user17281101
相关产品推荐
相关产品推荐

