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)

VBAVisibilityApps ScriptVisibility
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 modulen/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 them
function 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 Script snippets for more stuff like this

Continue reading about VBA to Google Apps Script here