Sunday, December 9, 2007

JavaScript Closures

Closures are a fairly advanced JavaScript feature which I have only seen discussed in special articles rather than tutorials. (Before anyone asks, I don't know how they got that name.) While I wish someone would write a tutorial that would introduce beginners to the concept, I don't have the time and might not have the expertise, so this is going to follow that trend.


First, let's have a definition. A closure is the scope of an outer function made accessible to all inner functions. When I look at code which uses closures, it seems like common sense that outer variables would be available from inner functions, but, at the same time, I wouldn't expect the effect sometimes. The effect can manifest similarly to the private declaration of properties in PHP or Java, or the static declaration of PHP as used at the first of a PHP function. Like both of these, a closure allows variables to be accessible only from within a certain context, across repeated calls to a certain set of functions.


JavaScript With(out) Closures
If JavaScript is written strictly without using closures, it can get pretty cluttered. Let's say I want to return Function B from Function A, then call Function B to manipulate variables initialized in Function A. (What a mouthful.)
<html>
    <head>
        <title>Titled Document</title>
        <script type="text/javascript">
            function funcA(){
                window.varA = 'a variable';
                    function funcB(){
                    alert(varA);
                }
                return funcB;
            }
            window.onload = function (){
                var funcB = funcA();
                alert(varA + '... Uh-oh...');
                    funcB();
            }
        </script>
    </head>
</html>
(The mention of window is unnecessary, but I want to make it obvious that varA is global.) This works, but, as the call to alert in window.onload shows, it also exposes your variables to overwriting (and hacking, but a hacker can always overwrite your functions anyway). This is a more private way to do it (still without closures):
<html>
    <head>
        <title>Titled Document</title>
        <script type="text/javascript">
            function funcA(){
                var result = {
                    varA: 'a variable';
                funcB: function (){
                    alert(this.varA);
                }
                return result;
            }
            window.onload = function (){
                var objA = funcA();
//                alert(varA + '... Uh-oh...');
                objA.funcB();
            }
        </script>
    </head>
</html>
But that's not exactly what we wanted. Because I was restricting myself from using closures, I had to use some other mechanism to do the same thing. I used a custom object, whose member 'funcB' is the focal point of the script. Here's a script that accomplishes the same thing as the previous two, but privately and without the object:
<html>
    <head>
        <title>Titled Document</title>
        <script type="text/javascript">
            function funcA(){
                var varA = 'a variable';
                function funcB(){
                    alert(varA);
                }
                return funcB;
            }
            window.onload = function (){
                var funcB = funcA();
//                alert(varA + '... Uh-oh...');
                funcB();
            }
        </script>
    </head>
</html>
Uncommenting the call to alert in window.onload causes an error, because varA is only defined within funcA's scope (= funcB's closure). Closures allow you to set up code boundaries at your convenience.


Final Notes
Pay attention if you declare several inner functions in one outer, particularly in a loop; the closure is a variable scope (as it exists when the inner function in question is executed) rather than a permanent snapshot of that scope from when the function was declared, and so there is one per call to the outer function, not one per inner function per call to the outer function. So this doesn't work as it would if closures were snapshots specific to inner functions:
function loopyLooper(){
    var demos = [];
    for(var i0 = 0; i0 < 10; i0++){
        demos[i0] = function(){
            alert(i0);
        };
    }
    return demos;
}
var demos = loopyLooper();
for(var demo in demos){
    demo();
}
Here's a correct solution to accomplish this in similar steps (but without using the closure):
function looper(){
    var demos = [];
    for(var i0 = 0; i0 < 10; i0++){
        demos[i0] = {
            func: function(){
                alert(this.num);
            },
            num: i0
        };
    }
    return demos;
};
var demos = looper();
for(var demo in demos){
    demo.func();
}

Here's a loop-less function that expects a snapshot instead of the actual scope:
function loopyLoopless(){
    var i = 0;
    function result(){
        alert(i);//should alert 0
    }
    i = 1;
    return result;
}



//user code

loopyLoopless()();//alerts 1 - The JavaScript interpreter must be broken!
And here's a correct version that preserves the user's control over when and in what context the resulting function is executed (while still using a closure):
function loopless(callback){
    var i = 0;
    callback(function(){
            alert(i);//should alert 0
        });
    i = 1;
}
//user code
loopless(function(result){
        result();//alerts 0
    });

As usual, discussion is invited.

Friday, December 7, 2007

JavaScript Format

I'm pretty picky about my code, so I want to detail my pet peeves and preferences. I'll assume that everyone knows what objects, arrays, strings, regular expressions (or "regexes"), numbers, functions, classes, methods, procedures, and properties are.


Operators
I put spaces on each side of my operators (=, +, -, *, /, %, ?, :, &&, ||, ==, !=, ===, !==, <, <=, >, >=, ^, ~, &, |, <<, >>, >>>), except for commas, colons used for assignment/labeling, exclamation points, and increment/decrement signs (++ and --). Commas and assignment/label colons get no spaces before and one space after.


Most JavaScript strings are enclosed in single quotes. This makes it easier to write HTML attributes and user-friendly quotes from JavaScript, and causes problems only if apostrophes get involved (in which case double quotes may be used). Alternatively, either type of quote may be escaped with a single backslash, and this is valid for both types within both types ("so \'this\' is valid").


Each line which would end with a semicolon in most languages will in my JavaScript. This way, code is more likely to be compatible in future versions of JavaScript, readability is enhanced (I believe), and some rare ambiguous situations are clarified for the browser. (I can't think of any of those ambiguous situations offhand, so you'll have to take my word for it and keep your eyes open.)


Curly brackets are always reason to break the line if there's anything in them; round brackets, square brackets, and ternary operators are only when their contents get too long for the screen. All such containers increase the indentation of any contained lines by one.


Iterators
Most people use alphabetical iterator identifiers (i, j, k, etc.) in their for loops. However, I got very frustrated and embarrassed (in my high school Computer Science class) by a simple bug - a spelling error - and now use numeric identifiers (i0, i1, i2, etc.) to make the difference between my first (i or i0) and second (j or i1) visually obvious. I also have a higher range of identifiers that don't cause confusion available; whereas someone else's 19th iterator might be called "zi," mine would simply be "i18."


When needed, my program-initialization procedure will be directly assigned to window.onload:
<html>
   <head>
      <title>Titled Document</title>
      <script type="text/javascript">
         function main(){
            //
         }
      </script>
   </head>
   <body onload="main();">
      
   </body>
</html>



Here's a demonstration of everything mentioned above:
var one = 1;
var two = one * 2;
var three = two + one;
var yup = true;
if(!yup || (three <= two)){
   alert('This can't be happening!');
}
for(var i0 = 0; i0 < 10; i0++){
   //
}
var object = {
   numbers: [ //This array really isn't long enough to break, but
      one,    //I want to show what I mean.
      two,    //(This applies to argument lists, too.)
      three
   ],
   do: function(){
      alert(function dummy(){
            //This is just a dummy.
         });//The round brackets don't break, but the curly ones do.
   }
}
var something = yup ? object : null;
switch(something){
   case object:
      //
      break;
   case null:
      //
      break;
   default:
      //
}
window.onload = function(){
   //Do something.
};

JavaScript Glossary

This post is currently under construction; please post any comments below.


Argument - An independent variable declared in a function's header and defined by the function's caller. An argument (or "arg") is only visible within the declared function's scope. If an argument uses the same identifier as another variable in a scope which contains the function, the argument hides the other variable.
function getArgument(arg){
alert('Your argument is ' + arg + '.');
}
getArgument('weak');// alerts "Your argument is weak."



Boolean - The binary (either true or false) datum type named after George Boole. Boolean values are immutable.


Class - A contrived notion in JavaScript which is nonetheless frequently used for transitioning class-based programmers into the prototype-based language. Classes are simulated in JavaScript via prototypes of constructors.


Constructor - A function called with new. By convention, constructor names should always be in UpperCamelCase. In the body of a constructor, the pseudo-variable this refers to each individual instance of that constructor that will ever exist.
function Foo(){
alert(this.constructor.name);
}
var foo = new Foo();//alerts "Foo"
Foo();//alerts "undefined" because this.constructor (i.e. window.constructor) doesn't exist in this case



Clone - An object which inherits every current property of its constructor's prototype.


Datum Type - One of at least 5 types of values: boolean; function; number; object; and string. The type of the literal undefined value is "undefined" but I don't consider that a real type. A value's type is returned by typeof value. See http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Operators:Special_Operators:typeof_Operator and http://en.wikipedia.org/wiki/Data_type.


Event - An object which represents a change in the browser's state; is passed as an argument to any event-handler as called by the browser.


Event-handler - A function called by the browser when a specific type of event occurs. Event-handlers can also be explicitly called by a script, but this is very uncommon.
window.onload = function (){
alert('Do something useful!');
};



Function - The datum type which represents sets of instructions to be executed by the browser at the prompting of either scripting or, in the case of event-handlers, the browser itself. Being objects, JavaScript functions are first-class. Functions are mutable.


Global - Owned by window. Global variables are accessible from every scope.


Local - Declared independently and therefore owned by no particular object.


Method - A function which happens to be the property of an object. Methods, like all other properties, should always have lowerCamelCase names (again, by widely accepted convention). In a method, this refers to the object in whose context the method was called.


Number - The signed, floating-point, numeric datum type. Numbers may be specified as either decimal, hexadecimal, or octal values. Numbers are immutable.


Object - The catch-all datum type. If a value is defined but doesn't fit in the boolean, function, number, or string groups (the members of which also being objects), then it's called an object. Object values are mutable.


Procedure - A method of no particular object (or of window). A function which is called as a property of no particular object is a local procedure; a function explicitly assigned to a property of window is a global procedure. Like methods', procedures' names should be in lowerCamelCase.


Prototype - An object whose properties are inherited by one or more clones. At its core, JavaScript is prototype-based.


String - The datum type of character sequences. Any length of non-newline characters delimited by two single- or double-quotes ( ' or " ) is a string. If a newline is interposed between the quotes, an "Unterminated string constant" error is issued. String values are immutable.