Google Script中for循环意外修改非目标对象问题及解决
编辑注:我定位到问题根源是此前代码中存在如下写法:
var summedImpsByWeekTable = impsByWeekTable
该写法并不会克隆对象,仅复制了指向同一对象的引用。正确的实现应使用如下写法:
var summedImpsByWeekTable = JSON.parse(JSON.stringify(budgetTable));
我保留了原始问题的全部内容,希望能帮到和我一样遇到同类问题、不知如何准确描述问题的开发者。
我一度怀疑是自己思路出错还是Google Script存在严重Bug(我更倾向于前者)。我几乎没有接受过专业的编程训练,基本都是边做边学,还请大家谅解。
我的代码运行效果不符合预期,因此我将代码尽可能简化来复现问题:当前的for循环修改了impsByWeekTable对象,但按照逻辑它本不应该改动这个对象。我的需求是让表格中的每个值等于对应行中该位置之前所有值的累加和,例如将数组[5,5,6,6]转换为[5,10,16,24]。我的复现代码如下:
Logger.log(impsByWeekTable) x = 1; for (y = 2; y <= numOfWeeks-2; y++) { for (z = 1; z <= y-2; z++) { summedImpsByWeekTable[x][y] = impsByWeekTable[x][y-z] + summedImpsByWeekTable[x][y]; } } Logger.log(impsByWeekTable)
具体问题表现为:for循环运行过程中impsByWeekTable被意外修改,第一次调用Logger.log输出的impsByWeekTable内容为:
[CTV, 55.0, 90909.09090909091, 109090.90909090909, 109090.90909090909, 72727.27272727274, 0.0]
第二次调用Logger.log输出的impsByWeekTable内容为:
[CTV, 55.0, 90909.09090909091, 200000.0, 400000.0, 763636.3636363636, 1454545.4545454546]
该现象明显不符合预期,因为for循环中没有编写任何修改impsByWeekTable的逻辑,我尝试了多种排查方法都未定位到根因,特此求助。
这是JavaScript中引用类型赋值的典型误区:
- 数组、对象在JavaScript中属于引用类型,直接使用
=赋值时,不会在内存中生成全新的对象副本,只是让新变量拿到原对象的内存地址,两个变量实际指向内存里的同一个对象。 - 执行
var summedImpsByWeekTable = impsByWeekTable后,所有对summedImpsByWeekTable的修改,本质上都是在操作原impsByWeekTable对象,所以哪怕循环逻辑里只写了修改summedImpsByWeekTable的代码,原对象的值也会同步发生变化。
修复方式就是在做累加计算前,对原始表格对象做深拷贝,生成完全独立的副本。你用到的JSON.parse(JSON.stringify(budgetTable))就是Google Script环境下简单易用的深拷贝实现,拷贝完成后两个对象互不干扰,修改用于累加计算的副本时,就不会改动原始的表格数据了。
内容的提问来源于stack exchange,提问作者Chris Verrill

