【问题标题】:google scripts; function within for loop stops it谷歌脚本; for 循环中的函数停止它
【发布时间】:2025-12-31 02:45:11
【问题描述】:

Google 表格:我创建了一个脚本,用于检测已更改的行并将更改发送到 slack。

我创建了一个 for 循环来遍历缓存中更改的行。 当调用 rowToObject() 时,for 循环在第一个条目处停止。如果我评论该函数,则循环按预期工作。

可能是什么原因?

// send all rows in cache to slack
function cacheToSlack() {
  var changes = JSON.parse(cache.get('changes'));
  Logger.log(changes);
  Logger.log(changes.length);


  for (i = 0; i < changes.length; i++) {

    // get edit range
    var row = changes[i]; 
    var rowValues = sheet.getRange(row, 1, 1, headerNum).getValues()[0];
    Logger.log(row);
    Logger.log(rowValues);
    rowToObject(rowValues);
  }

}

完整代码

// created cache for saving changed rows
var cache = CacheService.getDocumentCache();

// sheet and header data
var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("data");
var headers = sheet.getRange("1:1").getValues();
var headerNum = headers[0].length;

// track changed rows
function onChange(e) {
  var currentCache = cache.get('changes') || "[]";

  Logger.log('current');
  Logger.log(currentCache);

  Logger.log('row');
  Logger.log(e.range.getRow());

  var rowNum = e.range.getRow();
  var update = JSON.parse(currentCache).push(rowNum);
  cache.put('changes', JSON.stringify(update));

  Logger.log('change');
  Logger.log(cache.get('changes'));
}

function testCache() {
  // cache cannot save arrays
  cache.put('changes', JSON.stringify([156,157]));
  cacheToSlack();
}

// send all rows in cache to slack
function cacheToSlack() {
  var changes = JSON.parse(cache.get('changes'));
  Logger.log(changes);
  Logger.log(changes.length);


  for (i = 0; i < changes.length; i++) {

    // get edit range
    var row = changes[i];

    var rowValues = sheet.getRange(row, 1, 1, headerNum).getValues()[0];
    Logger.log(row);
    Logger.log(rowValues);
    rowToObject(rowValues);
  }

}

function rowToObject(row) {
  // create data object with headers as keys
  var data = {};

  for (i = 0; i < headerNum; ++i) {
    var header = headers[0][i];
    data[header] = row[i];
  }

  postToSlack(data);
}


function postToSlack(data) {
  Logger.log(data);
  // Create payload object
  var payloadObject = {
    blocks: [
      {
        type: "section",
        text: {
          type: "mrkdwn",
          text:
            "You have a new *<|Change or learning>*"
        }
      },
      {
        type: "section",
        fields: [
          {
            type: "mrkdwn",
            text: "*Channel:*\n" + data.channel
          },
          {
            type: "mrkdwn",
            text: "*Where:*\n" + data.where
          },
          {
            type: "mrkdwn",
            text: "*dateFrom:*\n" + data.dateFrom
          },
          {
            type: "mrkdwn",
            text: "*dateTo:*\n" + data.dateTo
          },
          {
            type: "mrkdwn",
            text: "*description:*\n" + data.description
          },
          {
            type: "mrkdwn",
            text: "*learning:*\n" + data.learning
          },
          {
            type: "mrkdwn",
            text: "*impact:*\n" + data.impact
          }
        ]
      }
    ]
  };

  // Stringify payload
  var payload = {
    payload: JSON.stringify(payloadObject)
  };

  // Build request
  var options = {
    method: "post",
    payload: payload
  };

  // Send to Slack
  Logger.log(options);
  //UrlFetchApp.fetch(SLACK_WEBHOOK_POST_URL, options);
}

function clearCache() {
  cache.remove('changes');
}

【问题讨论】:

  • 可能是一个范围界定问题,因为您在 rowToObject 和 main 函数中具有相同的 i。您能否将 rowToObject 函数中的 i 更改为 var j 并告诉我会发生什么?
  • @TanyaGupta 修复了它!谢谢,能告诉我是什么原因吗?
  • 太棒了!将在下面发布答案
  • 全局变量再次来袭! 总是将变量声明为作用域,例如在要使用该标识符的函数中使用var。这意味着你,for 循环! (较新的 JS 版本应酌情使用letconst

标签: javascript google-apps-script google-sheets


【解决方案1】:

在本地函数rowToObject 中将i 更改为var i 或其他变量名称(例如var j)应该可以修复错误。

上述错误是由于范围问题造成的。范围是关于变量(和函数)的可访问性,并指定执行变量的上下文。

rowToObject 中的变量 i 尚未初始化(即设置为 var i =0 而不仅仅是 i)。 i 的初始化使 i 本地化而不是全局化。当 i 未在本地函数内初始化时,范围被污染并被视为具有全局范围,因为您在cacheToSlack 中初始化了相同的变量 i

更多信息请见MDN Reference

【讨论】:

    【解决方案2】:

    问题是您没有将计数器i 定义为var,因此使其成为全局变量。

    当您在 rowToObject() 中重新定义 i 时,这会导致冲突。您可以通过使用var i 在本地定义变量来避免此问题。

    有关var 用法的更多信息,请参阅here

    【讨论】: