27
votes

How do you create a for-each loop in Google Apps Script?

I'm writing an email script with GAS, and I'd like to iterate through an array using a for-each loop, rather than a regular for-loop.
I've already seen this answer, but the object is undefined, presumably because the for loop doesn't work.

// threads is a GmailThread[]
for (var thread in threads) {
  var msgs = thread.getMessages();
  //msgs is a GmailMessage[]
  for (var msg in msgs) {
    msg.somemethod(); //somemethod is undefined, because msg is undefined.
  }
}


(I'm still new to javascript, but I know of a for-each loop from java.)

3
for (var thread of threads) { var msgs = thread.getMessages(); //msgs is a GmailMessage[] for (var msg in msgs) { ... } }Abhishek Singh
for...in iterates over an object's keys, not its values. This pattern is discouraged in JS as it will include custom prototypes added to arrays. If you want a more elegant solution I suggest thread.map(handleThread) or something along those linesRobin Gertenbach
'In later versions of javaScript, the forEach method was added to the Array object. The JavaScript engine used by Google Apps Script has this pattern available.' from ramblings.mcpher.com/Home/excelquirks/gooscript/loops. See my answer below.Jason Fry
Okay, I stand correctedphlaxyr

3 Answers

53
votes

Update: See @BBau answer below https://stackoverflow.com/a/60785941/5648223 for update on Migrating scripts to the V8 runtime.

In Google Apps Script:
When using "for (var item in itemArray)",
'item' will be the indices of itemArray throughout the loop (0, 1, 2, 3, ...).

When using "for each (var item in itemArray)",
'item' will be the values of itemArray throughout the loop ('item0', 
'item1', 'item2', 'item3', ...).

Example:

function myFunction() {
  var arrayInfo = [];
  
  arrayInfo.push('apple');
  arrayInfo.push('orange');
  arrayInfo.push('grapefruit');
  
  Logger.log('Printing array info using for loop.');
  for (var index in arrayInfo)
  {
    Logger.log(index);
  }
  Logger.log('Printing array info using for each loop.');
  for each (var info in arrayInfo)
  {
    Logger.log(info);
  }
}

Result:


    [17-10-16 23:34:47:724 EDT] Printing array info using for loop.
    [17-10-16 23:34:47:725 EDT] 0
    [17-10-16 23:34:47:725 EDT] 1
    [17-10-16 23:34:47:726 EDT] 2
    [17-10-16 23:34:47:726 EDT] Printing array info using for each loop.
    [17-10-16 23:34:47:727 EDT] apple
    [17-10-16 23:34:47:728 EDT] orange
    [17-10-16 23:34:47:728 EDT] grapefruit

23
votes

In the new V8 runtime Google has removed the for each loop. (V8 migration)

V8 Syntax

// V8 runtime
var obj = {a: 1, b: 2, c: 3};

for (var key in obj) {  // OK in V8
  var value = obj[key];
  Logger.log("value = %s", value);
}

Old Syntax deprecated

// Rhino runtime
var obj = {a: 1, b: 2, c: 3};

// Don't use 'for each' in V8
for each (var value in obj) {
  Logger.log("value = %s", value);
}
3
votes

From MDN, The for...in statement iterates over the enumerable properties of an object, in original insertion order. For each distinct property, statements can be executed. So you don't want a for...in statement. You could use forEach(), which executes a provided function once for each array element, though you don't have a function in your question so maybe that's not what you want. map() is another option, but it also needs a function, The map() method creates a new array with the results of calling a provided function on every element in the calling array.