Scoping JavaScript – An Overview

February 21st, 2012 Jon Theis, Consultant  (email the author)

Scope is an important concept in programming. For developers using object oriented languages, scope is an integral part of encapsulation. In simple terms, encapsulation can be defined as making the internal representation of an object (it’s implementation) hidden from the client that is using it. As an example, this concept is second nature to Java developers who define Interfaces and public methods to expose functionality to the outside world, but can hide the nitty gritty, implementation specific details in code not visible to the outside world (private methods for instance).
Can this same paradigm be applied to JavaScript? How can elements be scoped in JavaScript to provide for a clean interface to the outside world but still hide those low-level implementation details? Let’s discuss these questions by providing an overview of the different types of scope in JavaScript and then reviewing how they are implemented.

Global Scope

When a variable is defined outside of a function or is not explicitly defined, it is considered to be in global scope. Variables in this scope can be accessed from anywhere in a script. (Technically, it is added as an attribute of the Global Object provided by JavaScript).  You might equate this scope to public static in Java.
var globalVar = "This is a global variable";
globalNotExpliciltyDefined = "global variable not explicitly defined";
Global variables are often considered evil due to namespace issues and the problems they can introduce regarding program behavior and reliability.  Thus, their use is discouraged.

Public Scope

Public scope elements are accessible from the outside world.  To demonstrate, consider the following code snippet:
function ScopeObject(arg1){
    this.publicVariable = "public variable";
    this.paramMadePublic = arg1;
}

ScopeObject.prototype.publicMethod = function(){
    return "public method executed";
};

var myScopeObject = new ScopeObject("constructor param");
Here we define a constructor function, add a method to its prototype, and create an instance of it.  Given the existence of myScopeObject, the following code demonstrates how a client can access the publicly available elements of the instance:
myScopeObject.publicVariable;     //returns "public variable"
myScopeObject.publicMethod();     //returns "public method executed"
Public attributes are defined in the object’s constructor using this. i.e. this.publicVariable = “public variable”;
Methods that should be publicly available on all instances of an object can be added to the object’s prototype as shown above.

Private Scope

Hiding unnecessary implementation details from client code is a best practice regardless of the programming language being used.  The private scope facilitates this in JavaScript.
Parameters to functions are considered to be in private scope, as are variables defined with the var keyword inside the constructor.  Functions defined in the constructor are also considered to be in private scope.  Let’s add some private elements to the ScopeObject we defined earlier.
function ScopeObject(arg1){
     // arg1, when directly accessed in the constructor, is in private scope

     // ...existing public scope code omitted

    var privateVariable = "private variable";

    function privateMethod(){
        return "private method executed";
    }
}
Assuming we create an instance of our object again…
var myScopeObject = new ScopeObject("constructor param");
…trying to access a private variable using dot notation is not possible.  Trying to call the private method on an object instance also fails and will produce an error.
myScopeObject.privateVariable        //returns undefined
myScopeObject.privateMethod()      //produces TypeError: Object # has no method 'privateMethod'
The variable and method are hidden from direct access by the outside world.  What if we wanted to call the private method from our public method?  Sounds simple enough and is a practice familiar to Java and other OO developers.  Lets add another method to our object’s prototype like so:
ScopeObject.prototype.publicMethodCallsPrivateMethod = function(){

    // call the private method defined in the constructor
    privateMethod();

    return "public method calls private method executed";
};
Calling myScopeObject.publicMethodCallsPrivateMethod() returns TypeError: Object #<ScopeObject> has no method ‘privateMethod’. In JavaScript, a public method cannot call a private method.  If that’s the case, what’s the sense of using private methods?  Enter privileged scope.

Privilege Scope

Privileged scoped methods act as a bridge between the public and the private scopes.  Douglas Crockford in his post “Private Members In JavaScript” describes privileged methods this way:

A privileged method is able to access the private variables and methods, and is itself accessible to the public methods and the outside. It is possible to delete or replace a privileged method, but it is not possible to alter it, or to force it to give up its secrets.”
A privileged method is defined using the this keyword in the constructor.  Lets add a privileged method to our ScopeObject:
function ScopeObject(arg1){
  // ...existing public scope code omitted
  // ...existing private scope code omitted

  this.privilegedMethod = function(){
      return "privileged method executed";
  }
}
To demonstrate how this scope acts as a bridge between elements in public and private scope, let’s add an additional privileged method to our constructor that accesses the private variable and calls the private method.  Inside the ScopeObject constructor, add the following code:
  
this.privilegedMethodCallsPrivate = function(){

      console.log("in privileged method, privateVariable is : " + privateVariable);
      privateMethod();

      return "privileged method calls private executed";
  }
As a privileged method, this new method will not only be visible to the outside world (mimicking public scope), but calling myScopeObject.privilegedMethodCallsPrivate() succeeds because the privileged method has access to the private members of ScopeObject.

Summary

We discussed 4 types of scope: globalpublicprivate, and privileged.

Global: Variables in this scope are added to the JavaScript Global object and are available anywhere inside the script and to the outside world.  These should be avoided in favor of implementing encapsulation using the other scopes.
Public: Variables and methods in this scope are directly accessible by the outside world.  Variables in this scope are created in the constructor function using ‘this‘.  Methods of this scope are most often added to the prototype.
Private:  Not visible to the outside world.  Artifacts of this scope are limited without the use of privileged methods.  Variables of this scope are created using the ‘var‘ keyword in the constructor function.  Methods of this scope are created using the ‘function keyword in the constructor.
Privilege: The “bridge” or “glue” scope that permits access to private artifacts in the object but is also publicly available.  Methods of this scope are created using ‘this‘ in the object constructor.

Below is the final state of our sample code.  Some logging statements have been added so that execution can be traced when executing in the console.
function ScopeObject(arg1){
    this.publicVariable = "public variable";
    this.paramMadePublic = arg1;

    var privateVariable = "private variable";

    globalNotExpliciltyDefined = "global variable not explicitly defined";

    function privateMethod(){
        console.log("private method : executing...");
        return "private method executed";
    }

    this.privilegedMethod = function(){
        console.log("privileged method : executing...");
        return "privileged method executed";
    };

     this.privilegedMethodCallsPrivate = function(){
          console.log("privileged method calls private : executing...");

          console.log("in privileged method, privateVariable is : " + privateVariable);
          privateMethod();

          return "privileged method calls private executed";
     };

}

ScopeObject.prototype.publicMethod = function(){
    console.log("public method : executing...");
    return "public method executed";
};

ScopeObject.prototype.publicMethodCallsPrivateMthod = function(){
     console.log("public method calls private method : executing");
     privateMethod();
     return "public method calls private method executed";
};

Another way of controlling what is presented to a client user of an object in JavaScript is by using the Module Pattern, or its close cousin the Revealing Module Pattern. These patterns will be considered in a future post. In the meantime, what patterns do you use to control scope in your JavaScript? Please leave a comment below.

Be Sociable, Share!

Entry Filed under: Agile and Development

1 Comment Add your own

  • 1. Rui  |  April 12th, 2014 at 11:33 am

    publicMethodCallsPrivateMthod raises “ReferenceError: privateMethod is not defined”

Leave a Comment

Required

Required, hidden


+ nine = 12

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed

© 2010-2014 Summa All Rights Reserved