2

I am wondering if this is a feature of google apps script (or javascript as a whole for that matter) or a bug. I get a strange result when I call a function from inside a loop. Now, within the called function there is a loop that uses the same variable that the variable running on the calling loop and this seems to cause a problem. Here the code:

 function dudi() {
   var folderName='FormsGenerator';
   var ss=new Array(2);
   for(o=0;o<2;o++){
     var str='dudo' + o;
     trashFile(str,folderName);
     ss[o]=SpreadsheetApp.create(str);
     Logger.log(str);
   }
  }
 function trashFile(fileName,folderName){
   var folder=DocsList.getFolder(folderName);
   var lFolder=folder.getFiles();
   for(o=0;o < lFolder.length;o++){
     if(lFolder[o].getName() == fileName) {
       DocsList.getFileById(lFolder[o].getId()).setTrashed(true);
     }
   }

What happens is that the loop in the calling function stops after the first iteration. If in trashFile I change the loop index variable to "p" or I use a "var o=0" instead of a "o=0", the problem goes away. What am I doing wrong? Is this a well known feature or a bug? I have been programming in C and C++ for long years, but I am fairly new with javascript/GAS.

Max

Max
  • 171
  • 1
  • 1
  • 7

1 Answers1

1

Now, within the called function there is a loop that uses the same variable that the variable running on the calling loop and this seems to cause a problem.

The reason for the problem is that o isn't declared in either function, so you're falling prey to The Horror of Implicit Globals: In JavaScript, assigning to a variable that doesn't exist creates a global variable. (See below for more.) Since o ends up being a global variable, both functions use the same o, and interfere with each other.

Simply declare o within both functions (e.g.: var o;), and the problem will go away, because then each function uses its own local variable rather than a global.

This implicit globals thing is one of the flaws of the original design of JavaScript (all languages have design flaws). They've addressed this one in the new "strict" variant of the language: If you enable strict mode, assigning to a variable that doesn't exist causes an error rather than creating a global.

Examples: (Assume there is no declaration for a anywhere.)

Loose mode:

function foo() {
    a = "bar";    // <=== Creates a global variable called 'a'
}

Strict mode:

function foo() {
    "use strict";

    a = "bar";    // <=== Throws a ReferenceError
}

You can apply strict mode to all of your code by wrapping it a scoping function:

(function() {
    "use strict";

    function foo() {
        a = "bar";    // <=== Throws a ReferenceError
    }
})();

You can also apply it within a script tag by putting it at the top:

<script>
"use strict";
function foo() {
    a = "bar";    // <=== Throws a ReferenceError
}
</script>

This works both with inline script as with the above, and with .js files you load via src=. Beware, though, that if you do this at the top level of a .js file, you have to be careful when combining scripts! (This is one reason I always use scoping functions; the other is that I don't want to create any globals.)

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Thanks a lot for the enlightenment! I am actually picking up examples from James Ferrera's book on Google Scripts and the google developers pages. There I have seen many times loop like for(i in someList){}. I guess that also is wrong? i is a global variable? – Max Sep 10 '13 at 09:45
  • @Max: If `i` isn't declared anywhere, yes, that would make it an implicit global (in loose mode). Hopefully, though, `i` was declared somewhere (perhaps at the top of the function?). You've mentioned that you have C++ experience, so I'll warn you that JavaScript doesn't (currently) have block scope, only function scope, global scope, and closures. More [here](http://blog.niftysnippets.org/2008/03/poor-misunderstood-var.html) and [here](http://blog.niftysnippets.org/2008/02/closures-are-not-complicated.html) (disclosure: both are links to my blog). – T.J. Crowder Sep 10 '13 at 10:21
  • @TJCrowder, unfortunately there are plenty of examples in the GAS documentation which use the same idiom – Max Sep 10 '13 at 13:16
  • @Max: I'm both surprised and not surprised. Perhaps link one? You're **sure** they're not declaring the variable somewhere? – T.J. Crowder Sep 10 '13 at 13:19
  • This [example]https://developers.google.com/apps-script/articles/removing_duplicates?hl=en for instance – Max Sep 10 '13 at 13:25
  • But you can look for more examples searching for the string "for (i" in the google apps script search box. – Max Sep 10 '13 at 13:27
  • @Max: OMG, that example is rife with implicit globals (`i` and `j` at least) and other examples of not-best-practices, such as `new Array()` (which is much better written as `[]`) and using `for-in` to loop through arrays, which [isn't what it's for](http://blog.niftysnippets.org/2010/11/myths-and-realities-of-forin.html). (Here's how you loop through arrays: http://stackoverflow.com/questions/9329446/for-each-in-an-array-how-to-do-that-in-javascript/9329476#9329476) – T.J. Crowder Sep 10 '13 at 13:30