29

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.)

phlaxyr
  • 923
  • 1
  • 8
  • 22
  • for (var thread of threads) { var msgs = thread.getMessages(); //msgs is a GmailMessage[] for (var msg in msgs) { ... } } – Abhishek Singh Oct 11 '17 at 16:44
  • 1
    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 lines – Robin Gertenbach Oct 11 '17 at 16:45
  • '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 http://ramblings.mcpher.com/Home/excelquirks/gooscript/loops. See my answer below. – Jason Oct 11 '17 at 16:52
  • Okay, I stand corrected – phlaxyr Oct 11 '17 at 16:55

3 Answers3

55

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

Branden Huggins
  • 695
  • 7
  • 8
  • 1
    Good answer. Shorter version... `for each (var ColNum in [5,"hh",7]) { Logger.log(ColNum); }` – Stew-au Oct 23 '18 at 02:06
  • 2
    And this should never be used here since the Array class methods are available, such as `Array#forEach` or `Array#map` – tehhowch May 17 '19 at 22:26
  • 2
    The `for each` thing is interesting because it's not standard JavaScript (right?) but `Array#forEach` didn't work for my use case, since I needed to return from inside of the loop. I think this would be the equivalent of `for (... of ...)` in ES6. – gengkev Jan 23 '20 at 16:02
36

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);
}
B Bau
  • 479
  • 5
  • 8
  • 1
    I think this is the better and up-to-date answer. `for each` is not compatible in [V8](https://developers.google.com/apps-script/guides/v8-runtime/migration), and we should avoid using it. – KareemJ Jun 17 '20 at 02:13
3

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.

TheMaster
  • 45,448
  • 6
  • 62
  • 85
Jason
  • 514
  • 5
  • 21