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