VBA->JS: Scope, objects and keeping control (Syntax & Concept)

The previous post introduced Objects in JavaScript and showed two ways to declare and populate them. This entry provides more information about what can happen to objects that a VBA developer wouldn’t expect, as well as touch on the topic of variable scope. The reason for covering both in one place is the concern for minimizing unexpected problems and maintaining control of your code.

Scope
VBA developers are aware of the problem presented by global variables: not only can your project’s code access and change them from any point. Anyone else with a reference to your project can do the same. This makes it difficult to ensure that global variables will contain the value you expect. Thus, we try to avoid using them whenever possible.

Variables declared within a Sub or Function, on the other hand, are “protected” – they “live” completely within the procedure and have a limited scope. Further, they go “out-of-scope” (cease to exist in memory) when the procedure completes.

The same concern about visibility applies to Sub and Function procedures declared as “Public” (the VBA default). In this case, prefixing the procedure name with “Private” will make them invisible outside their module container.

Such considerations are one reason many object-oriented programming languages, such as VB and C#, have the concept of “classes”. This aids in exposing only those things to which outside code should have access, while safe-guarding the internal processes.

As mentioned in earlier posts, JavaScript does not have the concept of classes. (Actually, with the release of ECMAScript 6, it does, but it’s squeaky new and not yet widely supported.) It also does not have equivalent keywords to Private and Public. What’s more, all variables declared at the top code level as well as all variables not declared using the keyword var are global and exposed to any other code running in the “container” (window/web page). Just try to imagine the problems that could present…

In JavaScript, only variables declared using var within a function will have limited scope. These considerations lead to a – for VBA deveopers – unfamiliar way of constructing code in JavaScript. To our eyes, it appears unnecessarily convoluted with functions nested within functions. This makes reading and understanding JavaScript code examples available for Office Web Add-ins confusing, at best. To say nothing of the challenge of trying to write good code, oneself!

I won’t attempt to go into the details of all this – it’s been said better by others with a deeper understanding about what’s going on. Hopefully, though, with this background you’ll have a grasp of the “why” behind the concept known as “closures” and can follow explanations such as presented in the following links (which seem to me comparatively clearly set out):
http://www.w3schools.com/js/js_function_closures.asp
http://stackoverflow.com/questions/111102/how-do-javascript-closures-work (the reply referencing “JavaScript Closures for Dummies”).

This webpage summarizes the topic of scoping succinctly:
http://javascript.crockford.com/private.html

Objects: watch out!
Getting one’s head around JavaScript scope is bad enough. Coming to grips with what can happen to Objects is a real eye-opener!

From working with objects in VBA you’re accustomed to not being able to change at run-time what properties or methods they have, or how a method behaves. (And, for objects provided by Office you’re not able to change anything, at all.)

JavaScript is different in this regard and you need to be aware of what it is capable of so you don’t end up with problems that are difficult to track down.

The following discussion builds on the example of the Person object with its properties and methods as defined in the previous post.

var Person = {
  FirstName: "Jane",
  LastName: "Doe",
  Birthday: new Date(1999, 1, 0),
  FullName: function() {
    return this.FirstName + " " + this.LastName;
  },
  Age: function() {
    var dtToday = Date();
    var todayYear = new Date(dtToday).getFullYear();
    return todayYear - this.Birthday.getFullYear();
  }
}
Person.FullName();
//Result: "Jane Doe"

Logically, you can change the values assigned to the properties:
Person.FirstName = "Mary";
Person.FullName(); //Result: Mary Doe

What may surprise you is that you can also change the value (content) of a method at runtime:

Person.Age = function() {
  var dtToday = Date();
  var todayYear = new Date(dtToday).getFullYear();
  return this.FullName() + " is " + 
         (todayYear - this.Birthday.getFullYear()) 
         + " years old.";
}
Person.Age();
//Result: Jane Doe is 16 years old.

Even more astonishing is the fact that you can add and delete properties and methods at runtime:

Person.MiddleInitial = "S.";
delete Person.LastName;
Person.ShortName = function() {
    return this.FirstName + " " + this.MiddleInitial;
}
Person.ShortName();
//Result: Jane S.

If you’re beginning to think nothing is secure, you wouldn’t be far off the mark. Obviously, you have to be very careful when coding to not make any changes you don’t intend to make!

Newer versions of JavaScript (ECMAScript 5.1 and later) do come with ways to limit changes to objects, see:
http://www.2ality.com/2013/08/protecting-objects.html
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/seal

The latter link lists the earliest browser versions that support ECMAScript 5.1 and later. It’s important to note that the Office versions supporting Web Add-ins base on browser versions that support ECMAScript 5.1, which means limiting object visibility is possible in a Web Add-in.

In the next post we’ll look at some built-in functionality that can help your code determine what it’s dealing with.



Leave a Reply