Common pitfalls with JavaScript scope

I’m a firm believer that JavaScript’s flexibility is great for small projects with a single developer. But, its flexibility can become a seriously liability in medium to large projects if not managed properly. The ‘scope’ of a variable can cause some of the largest headaches for developers. And, in big projects tracking down an improperly scoped variable will take time, and it will try your patience.

In most cases, variables in JavaScript have two scopes: global and private. Scope is the context in which a variable is used. A global variable is defined outside of any function() in a JavaScript text block, and it can be accessed from inside any function(). Any change to a global variable will be reflected where ever else that variable is used. A private variable is defined only inside a function() and private variables are not accessible by other function()’s by definition. So a change to a private variable only changes it’s own value and doesn’t affect any other variable outside the scope of the function(). If you are new to scope, you may want to re-read this paragraph twice.

If you’ve been using JavaScript for any amount of time you’ll discover that simply misplacing a “var” statement in front of a variable causes it become global in scope. And, if you happen to already have a global variable somewhere else by the same name then these values can overwrite each other. If you are working on a project with thousands of lines of code and multiple .js libraries then your problems can get larger. I’ve accidentally deleted a “var” keyword in several cases and then spent a considerable head banging tracking it down.

To demonstrate these pitfalls, I’d rather show you in code what the problems are. Hopefully by reading this, and understanding a bit more about scope and by using best practices, you’ll avoid the common pitfalls as much as possible.

Scenario 1– properly defined private variables. This scenario demonstrates best practices for defining local variables within a function(). You can have privately scoped variables with the same name as global variables because of JavaScript obeying adherence to scope. Click here to try out this scenario.

  //This sets a global variable scope
  var color = "blue";

  function init() {

	var me = new Person("Andy");
	alert(" Private scoped name: " + me.name +
	   "\r\n Private scoped color: " + me.favoriteColor +
	   ", \r\n Global scoped color: " + color
	);

  }

  function Person(myname)
  {
	  //This creates a privately scoped variable
	  //Does not affect or change the globally scoped
	  //variable of same name
	  var color = "red";

	  //myname exists within the private scope of the function
	  //color is privately scoped
	  this.name = myname;
	  this.favoriteColor = color;
  }

Scenario 2 – improper use of a global variable. This scenario demonstrates forgetting to set “var” on the variable color. The value of the global variable named color is changed. If you use this pattern for manipulating global variables you are asking for trouble as your project grows larger. Click here to try out this scenario.

  //This sets a global variable scope
  var color = "blue";

  function init() {

	var me = new Person("Andy");
	alert(" Private scoped name: " + me.name +
	   "\r\n Private scoped color: " + me.favoriteColor +
	   ", \r\n Global scoped color: " + color
	);

  }

  function Person(myname)
  {
	  //This changes the globally scoped
	  //variable of same name
	  color = "red";

	  //myname exists within the private scope of the function
	  //color exists within the global scope of the application
	  this.name = myname;
	  this.favoriteColor = color;
  }

Scenario 3 – this scenario shows the best practice for passing in a global variable to a function(). By passing the global variable into someColor you protect the scope of it within the function(). Click here to try this scenario.

  //This sets a global variable scope
  var color = "blue";

  function init() {

	var me = new Person("Andy", color);
	alert(" Private scoped name: " + me.name +
	   "\r\n Private scoped color: " + me.favoriteColor +
	   ", \r\n Global scoped color: " + color
	);

  }

  function Person(myname, someColor)
  {
	  //myname exists within the private scope of the function
	  //someColor is a private scope, but it inherits the value
	  //of the variable passed to it.
	  this.name = myname;
	  this.favoriteColor = someColor;
  }

References:

Scope in JavaScript by Mike West
Variable Scope for New Programmers by Jonathan Snook

The Largest Conference For Mapping and Geospatial Developers – Esri DevSummit 2012

I’ll be presenting at the Esri DevSummit next week so if you are attending please swing by my sessions and say “hi”. If you aren’t familiar with Esri or the conference, about 1400 developers and other technical experts converge on Palm Springs, California every Spring to learn all things technical about building commercial and enterprise geographic information systems. There will be everything from introductory Dojo workshops to deep dives into the heart of our APIs.

If you’re around here’s my schedule. I’d be very interested to hear about what you are working on:

Monday,  March 26

Getting Started with the ArcGIS Web APIs – 8:30am – 11:45am, Pasadena Room. I’ll be presenting the portion related to our ArcGIS API for JavaScript.

Gettings Started with Smartphone and Tablet ArcGIS Runtime SDKs – 1:15pm – 4:45pm, Pasadena Room. In this session, I’ll be presenting on our ArcGIS Runtime SDK for Android.

Wednesday, March 28

Flex the World – 10:30am, Demo Theater 2. I’ll be presenting with my esteemed colleague Sajit Thomas on Apache Flex.

7 required improvements for the Web, HTML and JavaScript

Here’s my 2012 web developer wish list for improvements that I’d like to see happen in the web developer world. If HTML and JavaScript want to be considered enterprise ready for commercial-grade deployments then here’s some things that are needed today.

For clarity, I consider a commercial software deployment to be one that contains over one thousand lines of code, at least two custom .js libraries and involves at least two developers and some sort of code versioning system.

  1. Refactoring. Not having this capability continues to be a huge productivity issue for large projects. Try refactoring across six JavaScript libraries and 1200 lines of code using Notepad++.
  2. Even stronger scope enforcement in JavaScript classes. One wrong misspelling and you can spend fun filled hours (or days) tracking down a private variable that turned itself into a global variable.
  3. Built-in support for code comments. Visual Studio does a fine job, for example. But, it’s still kind of a hack to make it work. I’d like the built-in ability to create comments for methods and classes directly and then be able to access those comments via intellisense throughout any file in the project. Again, this is all about productivity by having this information accessible at your fingertips.
  4. Better built-in JavaScript checking for IDEs. I’d like to see built-in JSLint-like capabilities that have been updated to the latest HTML, JavaScript and CSS3 versions, and not some third party plug-in that’s optional.
  5. Best practice whitepapers. These would be whitepapers written by the browser vendors that provide guidelines on the correct patterns to use when building apps against their browsers. Seriously, it’s been roughly 21 years since we started using browsers and there’s no guidance at all from the powers that be.  Honestly, I’m stunned that these don’t exist. That would be similar to Microsoft publishing .NET and then not providing any conceptual help documentation.
  6. Official tools for browser certification and testing. The folks that build the browsers don’t give us a way to verify if we are building our apps in the best way possible. If these items existed, then quality could get a lot better, and we’d all learn a lot too.
  7. Slower browser release cycles. A slower release cycle for browsers and more improved security and stability. I already blogged about this here.