Closures, Namespaces, and Strict Mode

  1. Closures
    1. A closure is a special object that maintains the set of local variables for a function and their values after the function has returned
    2. When a function is defined, it keeps a pointer to the environment in which it was defined
    3. That means if a function is defined inside a function, it keeps a pointer to all the local variables in that function
    4. Unlike C++/Java, local variables do not necessarily go away as soon as the function is over
    5. You can use this to create a “function generator” – a function that creates functions
      function generateCounter(start) {
          return function() { return start++; };
      }
      
      var a = generateCounter(0);    // a will start counting at 0
      console.log(a());              // 0
      console.log(a());              // 1
      console.log(a());              // 2
      
      var b = generateCounter(100);  // b will start counting at 100
      console.log(b());              // 100
      console.log(b());              // 101
      
      console.log(a());              // 3
      
    6. Be careful – it's not copying the value; it's keeping a pointer to the variable
      1. Suppose we had 10 buttons with ids button1, button2, etc., and we wanted to set click handlers for each of them
        // Watch out!
        for (var i = 1; i <= 10; i++) {
        	var button = document.getElementById("button" + i);
        	button.addEventListener("click", 
        		function() { alert( "I'm button " + i ); },
        		false);
        }
        
      2. The single closure makes every button say I'm button 11!
      3. Need a function generator to create a separate closure for each function
        function makeClickHandler(x) {
            return function() { alert( "I'm button " + x ); };
        }
        
        for (var i = 1; i <= 10; i++) {
        	var button = document.getElementById("button" + i);
        	button.addEventListener("click", 
        		makeClickHandler(i), false);
        }
        
    7. Read more about closures here and here
  2. Global namespace
    1. Ideally, all JavaScript resides in .js files which are imported
      <script src="myscript.js"></script>
      
    2. Since multiple scripts might be used in a single page, there is a danger that they use the same global variables or function identifiers
    3. All functions and variables share the same global namespace in the Window object
    4. Browser add-ons or extensions also use JavaScript which could introduce collisions and conflicts
    5. Best to wrap all your variables and functions in a "package" via an object
      var myPackage = {
          name: "Bob Smith",
          location: "Searcy, AR";
          sayHello: function() { alert("Hello, " + this.name); }
      };
      
    6. Yahoo Module Pattern uses an immediately invoked anonymous function (allows for private and public properties and methods)
       
      myOrg.myProject.myModule = function() {
       
      	// "private" variables
      	var myPrivateVar = "Only accessible from within myOrg.myProject.myModule."
      
      	// "private" method
      	var myPrivateMethod = function() {
      		consol.log("Only accessible from within myOrg.myProject.myModule");
      	}
      
      	// Return object with public properties and methods
      	return {
      		myPublicProperty: "Accessible as myOrg.myProject.myModule.myPublicProperty."
      		
      		myPublicMethod: function() {
      			console.log("I'm accessible as myOrg.myProject.myModule.myPublicMethod.");
      
      			// Within myProject there is access to "private" vars and methods
      			console.log(myPrivateVar);
      			console.log(myPrivateMethod());
      
      			// Access public members using "this"
      			console.log(this.myPublicProperty);
      		}
      	}; 
      }();   // Execute immediately
      
    7. To ensure you are not using any global variables, use strict mode (see below)
  3. Strict mode
    1. Strict mode is a way to opt-in to a restricted variant of JavaScript
    2. Strict mode can catch many logic errors by changing them into exceptions
    3. It can apply to an entire script
      // Place at top to apply to entire script
      'use strict';
      
    4. Or just apply to specific functions
      // Strict function
      function strict() {
      	'use strict';
      	function nested() { return "And so am I!"; }
      	return "Hi!  I'm a strict mode function!  " + nested();
      }
      
      function notStrict() {
      	// Not in strict mode
      }
      
    5. Some of the effects (full list)
      1. Making an assignment which creates a global variable now throws an exception
        "use strict";
        globalVar = 99;  // throws a ReferenceError
        
        function test() {
        	anotherGlobal = 2;   // throws a ReferenceError
        }
        
      2. Prohibits the use of with
        "use strict";
        var x = 17;
        with (obj)   // Error!
        {
        	x;   // Ambiguous: x or obj.x?
        }				
        					
      3. Prevents duplicate parameter names and object properties
        "use strict";
        
        // Error: x is listed twice!
        function doSomething(x, y, x) {
            // etc.
        }
        
        // Error: foo is listed twice!
        var object = {
            foo: "bar",
            foo: "baz"
        };