Apps Script versus VBA scope

Scope

In Understanding Scope for VBA I showed some examples of the visibility of functions and variables across modules and procedures inside a VBA project. If you are moving to Apps Script (or JavaScript) from VBA, you'll need to understand the similarities and differences to get going.

Variable Scope within a project

Inside a project in both VBA and GAS you can have multiple modules (script files in GAS), each of which can contain functions (and subroutines in VBA). The scope of a variable refers to the its visibility across and within each of these functions.

Let's start with 'global' variables (the use of which I recommend you should try to minimize)


VBA Visibility Apps Script Visibility
Public globalVariable
Function a()
    Debug.print globalVariable
End Function
Across all modules in project var globalVariable;
function a() {
    Logger.log (globalVariable);
}
Across all modules in project
Dim globalVariable
Function a()
    Debug.print globalVariable
End Function
 Only in this module   n/a

Conclusion - Global variables

In GAS there is no special distinction between having separate modules and one single module from the perspective of variable visibility. Variables declared outside the scope of a function are visible across all modules. In VBA you would need to use Public rather than Dim to achieve the same level of 'globalness'. Variable declared outside a function in VBA are global for all functions in that module but not visible by other modules.

However ...

JavaScript (and GAS) has the concept of lexical scoping, which allows you to duplicate the module level scoping capability of VBA.

VBAVisibilityApps ScriptVisibility
Dim message as String

Function init()
  message = "hello"
End Function

Function say() 
  Debug.print message
End Function

Function myFunction()
  init
  say
End Function
    
In this VBA snippet, where the functions are declared inside the same module, both init and say have access to message, so running myFunction() would give the same result as the GAS example above.function myFunction() {
  var message = "hello";
  function say() {
    Logger.log(message);
  }
  say();
}
message is visible inside say() because functions declared inside other  functions have access to variables in outer scopes
Function init()
   Dim message as String
  message = "hello"
End Function

Function say() 
  ' message would be undefined
  Debug.print message
End Function

Function myFunction()
  init
  say
End Function
message is declared in the init function and would not be visible in the say() function function myFunction() {
  var message = "hello";
  say();
}

function say() {
   // message is undefined
  Logger.log(message);
}
Imessage would not be visible inside say() because it was say() is not declared inside myFunction()








Namespaces

In Namespaces in libraries and scripts I cover how you can cause scripts in GAS to behave a little like Modules in VBA from the perspective of variable scoping, taking advantage of this lexical scoping characteristic. I find this technique good practice - if you have created separate scripts then logically separating them reinforces that.

VBAVisibilityApps ScriptVisibility
Dim message as String

Function init()
  message = "hello"
End Function

Function say() 
  Debug.print message
End Function

Message is visible from all functions in the module. However we haven't executed anything yet.function MyModule = (function() {
 
  var mm = {};
  var message = "hello";

  function myFunction() {

    
    function say() {
      Logger.log(message);
    }
    say();
  }
    return mm;
})();

Message is visible from all functions declared within in MyModule. What's happening here is that we are creating an object filling it with functions and variables and returning it for use by other modules.
Nothing is being executed here. All we are doing is defining the functions - just as in the VBA equivalent. However, unlike the VBA version myFunction() and message are not visible outside of MyModule so cannot be executed... so...
Dim message as String

Function init()
  message = "hello"
End Function

Function say() 
  Debug.print message
End Function

Function myFunction()
  init
  say
End Function
Here we are defining the init and say function, and then executing themfunction MyModule = (function() {
  
  var mm = {};
  mm.message = "hello";

  mm.say = function () {

      Logger.log(message);
  }
    return mm;
})();

MyModule.say();
To make the functions of MyModule visible to others, we need to make them properties of myModule, which is going to be visible through the global MyModule variable.

We can then execute the say function contained within the MyModule object.


See Google Apps Scripts snippets for more stuff like this.

Comments