Learning JavaScript



    Basic JavaScript
    Dynamic Variable Typing
     
    //Dynamic typing of numbers 
    var x = 10.5 ; 
    var y = 20.5 ; 
    var z = x+y  ;
    test( z ==  31 , "Equal values" );
    test( z === 31 , "Euqal values and type" );
    
    //Dynamic typing of Strings
    var name1 = "Jalal Hejazi" ;
    var name2 = 'Jalal Hejazi' ; 
    
    test ( name1 === name2 , "name1 is name2" )
    
        //Dynamic typing of Instance of a Function 
        var now  = new Date() 
        var yyyy = now.getFullYear()
        log (now)
        log ( "Year:  " +  yyyy )
        log ( "time:  " + now.toLocaleTimeString() )
    
    
    Unit test helper methods
    // Test for True:
    test( 1==1, "I'am true" );
    var x = 1 ;
    test( x==1, "I'll pass. x is equal a value " );
    test( x===1, "I'll pass. Same type and value" );
    test( true, "I'll pass. true is true" );
    test( "Jalal", "Jalal is a true string" );
    
    // Test for False:
    test( false, "I'll fail." );
    test( null, "So will I." );
    
    // Test for an error:
    error( "I'm an error!" );
    
    // Log to test for values:
    var a = "A B C D E F G H I J K L M N"
    log( a );
    
    
    Defining Functions
    Many Ways to define functions?
     
    function isOK(){ return true; } 
    
    var canFly = function(){ return true; }; 
    
    window.Open = function(){ return true; }; 
    
    log(isOK); 
    log(canFly);
    log(window.Open) ;
    
    
    Does the order of function definition matter?
     
     var canFly      = function() { return true; }; 
     window.isDeadly = function() { return true; }; 
    
     test( isOK() && canFly() && isDeadly(), "Still works, even though isOK is defined later!" ); 
    
     function isOK(){ return true; } 
     
    Where can assignments be accessed?
     
     test( typeof canFly   == "undefined", "canFly is not yet defined"  ); 
     test( typeof isDeadly == "undefined", "isDeadly is not yet defined"); 
     
     var canFly      = function(){ return true; }; 
     window.isDeadly = function(){ return true; }; 
    
     test( typeof canFly   != "undefined", "canFly is now defined"  ); 
     test( typeof isDeadly != "undefined", "isDeadly is now defined"); 
     
     test( canFly() === true , "canFly is now accessible and equal True"  ); 
    
     
    Can functions be defined below return statements?
     
       function TestMe()
       { 
        test( F1(), "We'll never get below the return, but that's OK!" ); 
        return F1();
            // This function will never be defined because of the return
            function F1(){ return "You can call me?"; } 
       } 
    
     // Call the function: 
     TestMe(); 
    
     // Is F1 defined?
     test( typeof F1 == "undefined", "Is not yet defined"  ); 
    
     // Try to call the undefined function :-)
     F1() ;
    
     
    Named Functions
    We can refer to a function, within itself, by its name.
     
    function yell(n){ 
       return n > 0 ? yell(n-1) + "a" : "hiy"; 
     } 
     
     log( yell(0) ); 
      log( yell(1) ); 
       log( yell(2) ); 
        log( yell(3) ); 
         log( yell(4) ); 
     
    
     test( yell(4) == "hiyaaaa", "Calling the function by itself comes naturally." ); 
     
     
    What is the name of a function?
     
    var ninja = function myNinja(){ 
       test( ninja == myNinja, "This function is named two things - at once!" ); 
     }; 
    
     ninja(); 
    
     test( typeof myNinja == "undefined", "But myNinja isn't defined outside of the function." ); 
     
     log( ninja );
     
     
    We can even do it if we're an anonymous function that's an object property.
     
     var ninja = { 
       yell: function(n){ 
         return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
       } 
     }; 
     
     // ninja is the object
     // yell(n) is a function with a parameter
     test( ninja.yell(4) == "hiyaaaa", "Object property as anonymous function" ); 
     
    But what happens when we remove the original object?
     var ninja = { 
       yell: function(n){ 
         return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
       } 
     }; 
     test( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 
    
     var samurai = { yell: ninja.yell }; 
    
     // But what happens when we remove the original object?
     var ninja = null; // <- ninja is now null ( removed )
      
     try { 
      log( samurai.yell(4) ); 
      
     } catch(e){ 
       test( false, "Uh, this isn't good! Where'd ninja.yell go?" ); 
     } 
      
     
    Let's give the anonymous function a name!
     
    var ninja = { 
       yell: function yell(n){ 
         return n > 0 ? yell(n-1) + "a" : "hiy"; 
       } 
     }; 
    
     test( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" ); 
      
     var samurai = { yell: ninja.yell }; 
     
     // This will initialize the original object 
     var ninja = {}; 
     
     test( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." ); 
     
    What if we don't want to give the function a name?
     var ninja = { 
       yell: function(n){ 
         return n > 0 ? arguments.callee(n-1) + "a" : "hiy"; 
       } 
     }; 
    
     test( ninja.yell(4) == "hiyaaaa", "arguments.callee is the function itself." ); 
     
     function myFunctionName(a,b,c,d) {
      log ("Function name is " + arguments.callee.name );
      log ("arguments count is " + arguments.length);
     }
    
     myFunctionName(1,2,3,4) ;
     
     
    Functions as Objects
    How similar are functions and objects?
     var obj = {}; 
     var fn = function(){}; 
     test( obj && fn, "Both the object and function exist." ); 
    How similar are functions and objects?
     var obj = {}; 
     var fn = function(){}; 
     obj.prop = "some value"; 
     fn.prop = "some value"; 
     test( obj.prop == fn.prop, "Both are objects, both have the property." ); 
    What happens if a function is an object property?
     var katana = { 
       isSharp: true, 
       use: function(){ 
         this.isSharp = !this.isSharp; 
       } 
     }; 
     katana.use();
     test( !katana.isSharp, "Verify the value of isSharp has been changed." );
    What exactly does context represent?
     function katana(){ 
       this.isSharp = true; 
     } 
     katana(); 
     test( isSharp === true, "A global object now exists with that name and value." ); 
      
     var shuriken = { 
       toss: function(){ 
         this.isSharp = true; 
       } 
     }; 
     shuriken.toss(); 
     test( shuriken.isSharp === true, "When it's an object property, the value is set within the object." ); 
    How can we change the context of a function?
     var object = {}; 
     function fn(){ 
       return this; 
     } 
     test( fn() == this, "The context is the global object." ); 
     test( fn.call(object) == object, "The context is changed to a specific object." ); 
    Different ways of changing the context:
     function add(a, b){ 
       return a + b; 
     } 
     test( add.call(this, 1, 2) == 3, ".call() takes individual arguments" ); 
     test( add.apply(this, [1, 2]) == 3, ".apply() takes an array of arguments" ); 
    QUIZ: How can we implement looping with a callback?
     function loop(array, fn){ 
       for ( var i = 0; i < array.length; i++ ) {
         // Implement me!
       }
     } 
     var num = 0; 
     loop([0, 1, 2], function(value){ 
       test(value == num++, "Make sure the contents are as we expect it."); 
       test(this instanceof Array, "The context should be the full array.");
     }); 
    A possible solution for function looping:
     function loop(array, fn){ 
       for ( var i = 0; i < array.length; i++ ) 
         fn.call( array, array[i], i );
     } 
     var num = 0; 
     loop([0, 1, 2], function(value, i){ 
       test(value == num++, "Make sure the contents are as we expect it."); 
       test(this instanceof Array, "The context should be the full array.");
     }); 
    Instantiation
    What does the new operator do?
     function Ninja(){
       this.name = "Ninja";
     } 
      
     var ninjaA = Ninja(); 
     test( !ninjaA, "Is undefined, not an instance of Ninja." ); 
      
     var ninjaB = new Ninja(); 
     test( ninjaB.name == "Ninja", "Property exists on the ninja instance." ); 
    We have a 'this' context that is a Ninja object.
     function Ninja(){ 
       this.swung = false; 
        
       // Should return true 
       this.swingSword = function(){ 
         this.swung = !this.swung; 
         return this.swung;
       }; 
     } 
      
     var ninja = new Ninja(); 
     test( ninja.swingSword(), "Calling the instance method." ); 
     test( ninja.swung, "The ninja has swung the sword." );
     
     var ninjaB = new Ninja();
     test( !ninjaB.swung, "Make sure that the ninja has not swung his sword." );
    QUIZ: Add a method that gives a name to the ninja.
     function Ninja(name){
       // Implement!
    }
    
    var ninja = new Ninja("Jalal");
    test( ninja.name == "Jalal", "The name has been set on initialization" );
    
    ninja.changeName("Bob");
    test( ninja.name == "Bob", "The name was successfully changed." );
    Add a new property and method to the object.
     function Ninja(name){
       this.changeName = function(name){
         this.name = name;
       };
    
       this.changeName( name );
    }
    
    var ninja = new Ninja("Jalal");
    test( ninja.name == "Jalal", "The name has been set on initialization" );
    
    ninja.changeName("Bob");
    test( ninja.name == "Bob", "The name was successfully changed." );
    What happens when we forget to use the new operator?
    function User(first, last){ 
       this.name = first + " " + last; 
     } 
      
     var user = User("Jalal", "Hejazi"); 
     test( typeof user == "undefined", "Since new wasn't used, the instance is undefined." ); 
    What happens when we forget to use the new operator? (cont.)
     function User(first, last){ 
       this.name = first + " " + last; 
     } 
      
     window.name = "Hejazi"; 
     var user = User("Jalal", name); 
      
     test( name == "Jalal Hejazi", "The name variable is accidentally overridden." ); 
    We need to make sure that the new operator is always used.
     function User(first, last){ 
       if ( !(this instanceof User) ) 
         return new User(first, last); 
        
       this.name = first + " " + last; 
     } 
      
     var name = "Hejazi"; 
     var user = User("Jalal", name); 
      
     test( user, "This was defined correctly, even if it was by mistake." ); 
     test( name == "Hejazi", "The right name was maintained." ); 
    QUIZ: Is there another, more generic, way of doing this?
     function User(first, last){ 
       if ( !(this instanceof ___) ) 
         return new User(first, last); 
        
       this.name = first + " " + last; 
     } 
      
     var name = "Hejazi"; 
     var user = User("Jalal", name); 
      
     test( user, "This was defined correctly, even if it was by mistake." ); 
     test( name == "Hejazi", "The right name was maintained." ); 
    A solution using arguments.callee.
     function User(first, last){ 
       if ( !(this instanceof arguments.callee) ) 
         return new User(first, last); 
        
       this.name = first + " " + last; 
     } 
      
     var name = "Hejazi"; 
     var user = User("Jalal", name); 
      
     test( user, "This was defined correctly, even if it was by mistake." ); 
     test( name == "Hejazi", "The right name was maintained." ); 
    Flexible Arguments
    Using a variable number of arguments to our advantage.
     function merge(root){ 
       for ( var i = 1; i < arguments.length; i++ ) 
         for ( var key in arguments[i] ) 
           root[key] = arguments[i][key]; 
       return root; 
     } 
      
     var merged = merge({name: "Jalal"}, {city: "Copenhagen"}); 
     test( merged.name == "Jalal", "The original name is intact." ); 
     test( merged.city == "Copenhagen", "And the city has been copied over." ); 
    How can we find the Min/Max number in an array?
     function smallest(array){ 
       return Math.min.apply( Math, array ); 
     } 
     function largest(array){ 
       return Math.max.apply( Math, array ); 
     } 
     test(smallest([0, 1, 2, 3]) == 0, "Locate the smallest value."); 
     test(largest([0, 1, 2, 3]) == 3, "Locate the largest value."); 
    Another possible solution:
     function smallest(){ 
       return Math.min.apply( Math, arguments ); 
     } 
     function largest(){ 
       return Math.max.apply( Math, arguments ); 
     } 
     test(smallest(0, 1, 2, 3) == 0, "Locate the smallest value."); 
     test(largest(0, 1, 2, 3) == 3, "Locate the largest value."); 
    Uh oh, what's going wrong here?
     function highest(){ 
       return arguments.sort(function(a,b){
         return b - a;
       });
     } 
     test(highest(1, 1, 2, 3)[0] == 3, "Get the highest value."); 
     test(highest(3, 1, 2, 3, 4, 5)[1] == 4, "Verify the results."); 
    QUIZ: We must convert array-like objects into actual arrays. Can any built-in methods help?
     // Hint: Arrays have .slice and .splice methods which return new arrays.
    function highest(){ 
       return makeArray(arguments).slice(1).sort(function(a,b){
         return b - a;
       });
     } 
    
     function makeArray(array){
       // Implement me!
     }
    
     // Expecting: [3,2,1]
     test(highest(1, 1, 2, 3)[0] == 3, "Get the highest value."); 
     // Expecting: [5,4,3,2,1]
     test(highest(3, 1, 2, 3, 4, 5)[1] == 4, "Verify the results."); 
    We can use built-in methods to our advantage.
     function highest(){ 
       return makeArray(arguments).sort(function(a,b){
         return b - a;
       });
     } 
    
     function makeArray(array){
       return Array().slice.call( array );
     }
    
     test(highest(1, 1, 2, 3)[0] == 3, "Get the highest value."); 
     test(highest(3, 1, 2, 3, 4, 5)[1] == 4, "Verify the results."); 
    QUIZ: Implement a multiplication function (first argument by largest number).
     function multiMax(multi){ 
       // Make an array of all but the first argument
       var allButFirst = ___;
    
       // Find the largest number in that array of arguments
       var largestAllButFirst = ___;
    
       // Return the multiplied result
       return multi * largestAllButFirst;
     } 
     test( multiMax(3, 1, 2, 3) == 9, "3*3=9 (First arg, by largest.)" ); 
    We can use call and apply to build a solution.
     function multiMax(multi){ 
       // Make an array of all but the first argument
       var allButFirst = Array().slice.call( arguments, 1 );
    
       // Find the largest number in that array of arguments
       var largestAllButFirst = Math.max.apply( Math, allButFirst );
    
       // Return the multiplied result
       return multi * largestAllButFirst;
     } 
     test( multiMax(3, 1, 2, 3) == 9, "3*3=9 (First arg, by largest.)" ); 
    Closures
    A basic closure.
     var num = 10;
    
     function addNum(myNum){
       return num + myNum;
     }
    
     test( addNum(5) == 15, "Add two numbers together, one from a closure." );
    But why doesn't this work?
     var num = 10;
    
     function addNum(myNum){
       return num + myNum;
     }
     
     num = 15;
    
     test( addNum(5) == 15, "Add two numbers together, one from a closure." );
    Closures are frequently used for callbacks.
     var results = jQuery("#results").html("<li>Loading...</li>"); 
    
     jQuery.get("test.html", function(html){ 
       results.html( html ); 
       test( results, "The element to append to, via a closure." ); 
     }); 
    They're also useful for timers.
     var count = 0; 
      
     var timer = setInterval(function(){ 
       if ( count < 5 ) { 
         log( "Timer call: ", count );
         count++; 
       } else { 
         test( count == 5, "Count came via a closure, accessed each step." ); 
         test( timer, "The timer reference is also via a closure." ); 
         clearInterval( timer ); 
       } 
     }, 100); 
    and they're also frequently used when attaching event listeners.
     var count = 1;
     var elem = document.createElement("li");
     elem.innerHTML = "Click me!";
     elem.onclick = function(){
       log( "Click #", count++ );
     };
     document.getElementById("results").appendChild( elem );
     test( elem.parentNode, "Clickable element appended." );
    Private properties, using closures.
     function Ninja(){ 
       var slices = 0; 
        
       this.getSlices = function(){ 
         return slices; 
       }; 
       this.slice = function(){ 
         slices++; 
       }; 
     } 
      
     var ninja = new Ninja(); 
     ninja.slice(); 
     test( ninja.getSlices() == 1, "We're able to access the internal slice data." ); 
     test( ninja.slices === undefined, "And the private data is inaccessible to us." ); 
    QUIZ: What are the values of the variables?
    var a = 5;
    function runMe(a){
      test( a == ___, "Check the value of a." );
    
      function innerRun(){
        test( b == ___, "Check the value of b." );
        test( c == ___, "Check the value of c." );
      }
    
      var b = 7;
      innerRun();
      var c = 8;
    }
    runMe(6);
    
    for ( var d = 0; d < 3; d++ ) {
      setTimeout(function(){
        test( d == ___, "Check the value of d." );
      }, 100);
    }
    The last one is quite tricky, we'll revisit it.
    var a = 5;
    function runMe(a){
      test( a == 6, "Check the value of a." );
    
      function innerRun(){
        test( b == 7, "Check the value of b." );
        test( c == undefined, "Check the value of c." );
      }
    
      var b = 7;
      innerRun();
      var c = 8;
    }
    runMe(6);
    
    for ( var d = 0; d < 3; d++ ) {
      setTimeout(function(){
        test( d == 3, "Check the value of d." );
      }, 100);
    }
    Temporary Scope
    Self-executing, temporary, function
     (function(){
       var count = 0; 
     
       var timer = setInterval(function(){ 
         if ( count < 5 ) { 
           log( "Timer call: ", count ); 
           count++; 
         } else { 
           test( count == 5, "Count came via a closure, accessed each step." ); 
           test( timer, "The timer reference is also via a closure." ); 
           clearInterval( timer ); 
         } 
       }, 100);
    })();
    
    test( typeof count == "undefined", "count doesn't exist outside the wrapper" );
    test( typeof timer == "undefined", "neither does timer" );
    Now we can handle closures and looping.
    for ( var d = 0; d < 3; d++ ) (function(d){
      setTimeout(function(){
        log( "Value of d: ", d );
        test( d == d, "Check the value of d." );
      }, d * 200);
    })(d);
    The anonymous wrapper functions are also useful for wrapping libraries.
     (function(){ 
       var myLib = window.myLib = function(){ 
         // Initialize 
       }; 
      
       // ... 
     })(); 
    Another way to wrap a library:
     var myLib = (function(){ 
       function myLib(){ 
         // Initialize 
       } 
      
       // ... 
        
       return myLib; 
     })(); 
    QUIZ: Fix the broken closures in this loop!
     var count = 0;
     for ( var i = 0; i < 4; i++ ) {
       setTimeout(function(){
         test( i == count++, "Check the value of i." );
       }, i * 200);
     }
    A quick wrapper function will do the trick.
     var count = 0;
     for ( var i = 0; i < 4; i++ ) (function(i){
       setTimeout(function(){
         test( i == count++, "Check the value of i." );
       }, i * 200);
     })(i);
    Function Prototypes
    Adding a prototyped method to a function.
     function Ninja(){} 
      
     Ninja.prototype.swingSword = function(){ 
       return true; 
     }; 
      
     var ninjaA = Ninja(); 
     test( !ninjaA, "Is undefined, not an instance of Ninja." ); 
      
     var ninjaB = new Ninja(); 
     test( ninjaB.swingSword(), "Method exists and is callable." ); 
    Properties added in the constructor (or later) override prototyped properties.
     function Ninja(){ 
       this.swingSword = function(){ 
         return true; 
       }; 
     } 
      
     // Should return false, but will be overridden 
     Ninja.prototype.swingSword = function(){ 
       return false; 
     }; 
      
     var ninja = new Ninja(); 
     test( ninja.swingSword(), "Calling the instance method, not the prototype method." );
    Prototyped properties affect all objects of the same constructor, simultaneously, even if they already exist.
     function Ninja(){ 
       this.swung = true; 
     } 
      
     var ninjaA = new Ninja(); 
     var ninjaB = new Ninja(); 
      
     Ninja.prototype.swingSword = function(){ 
       return this.swung; 
     }; 
      
     test( ninjaA.swingSword(), "Method exists, even out of order." );
     test( ninjaB.swingSword(), "and on all instantiated objects." ); 
    QUIZ: Make a chainable Ninja method.
     function Ninja(){ 
       this.swung = true; 
     } 
      
     var ninjaA = new Ninja(); 
     var ninjaB = new Ninja(); 
      
     // Add a method to the Ninja prototype which
     // returns itself and modifies swung
      
     test( !ninjaA.swing().swung, "Verify that the swing method exists and returns an instance." );
     test( !ninjaB.swing().swung, "and that it works on all Ninja instances." ); 
    The chainable method must return this.
     function Ninja(){ 
       this.swung = true; 
     } 
      
     var ninjaA = new Ninja(); 
     var ninjaB = new Ninja(); 
     
     Ninja.prototype.swing = function(){
       this.swung = false;
       return this;
     }; 
      
     test( !ninjaA.swing().swung, "Verify that the swing method exists and returns an instance." );
     test( !ninjaB.swing().swung, "and that it works on all Ninja instances." ); 
    Instance Type
    Examining the basics of an object.
     function Ninja(){} 
      
     var ninja = new Ninja(); 
    
     test( typeof ninja == "object", "However the type of the instance is still an object." );   
     test( ninja instanceof Ninja, "The object was instantiated properly." ); 
     test( ninja.constructor == Ninja, "The ninja object was created by the Ninja function." ); 
    We can still use the constructor to build other instances.
     function Ninja(){}
     var ninja = new Ninja(); 
     var ninjaB = new ninja.constructor(); 
      
     test( ninjaB instanceof Ninja, "Still a ninja object." ); 
    QUIZ: Make another instance of a Ninja.
    var ninja = (function(){
      function Ninja(){}
      return new Ninja();
    })();
    
    // Make another instance of Ninja
    var ninjaB = ___;
    
    test( ninja.constructor == ninjaB.constructor, "The ninjas come from the same source." );
    QUIZ: Use the .constructor property to dig in.
    var ninja = (function(){
      function Ninja(){}
      return new Ninja();
    })();
    
    // Make another instance of Ninja
    var ninjaB = new ninja.constructor();
    
    test( ninja.constructor == ninjaB.constructor, "The ninjas come from the same source." );
    Inheritance
    The basics of how prototypal inheritance works.
     function Person(){} 
     Person.prototype.dance = function(){}; 
      
     function Ninja(){} 
      
     // Achieve similar, but non-inheritable, results 
     Ninja.prototype = Person.prototype; 
     Ninja.prototype = { dance: Person.prototype.dance }; 
    
     test( (new Ninja()) instanceof Person, "Will fail with bad prototype chain." );
      
     // Only this maintains the prototype chain 
     Ninja.prototype = new Person(); 
      
     var ninja = new Ninja(); 
     test( ninja instanceof Ninja, "ninja receives functionality from the Ninja prototype" ); 
     test( ninja instanceof Person, "... and the Person prototype" ); 
     test( ninja instanceof Object, "... and the Object prototype" ); 
    QUIZ: Let's try our hand at inheritance.
     function Person(){}
     Person.prototype.getName = function(){
       return this.name;
     };
    
     // Implement a function that inherits from Person
     // and sets a name in the constructor
    
     var me = new Me();
     test( me.getName(), "A name was set." );
    The result is rather straight-forward.
     function Person(){}
     Person.prototype.getName = function(){
       return this.name;
     };
    
     function Me(){
       this.name = "Jalal Hejazi";
     }
     Me.prototype = new Person();
    
     var me = new Me();
     test( me.getName(), "A name was set." );
    Built-in Prototypes
    We can also modify built-in object prototypes.
     if (!Array.prototype.forEach) { 
       Array.prototype.forEach = function(fn){ 
         for ( var i = 0; i < this.length; i++ ) { 
           fn( this[i], i, this ); 
         } 
       }; 
     } 
      
     ["a", "b", "c"].forEach(function(value, index, array){ 
       test( value, "Is in position " + index + " out of " + (array.length - 1) ); 
     }); 
    Beware: Extending prototypes can be dangerous.
     Object.prototype.keys = function(){ 
       var keys = []; 
       for ( var i in this ) 
         keys.push( i ); 
       return keys; 
     }; 
      
     var obj = { a: 1, b: 2, c: 3 }; 
    
     test( obj.keys().length == 3, "We should only have 3 properties." );
    
     delete Object.prototype.keys;
    Enforcing Function Context
    What happens when we try to bind an object's method to a click handler?
     var Button = { 
       click: function(){ 
         this.clicked = true; 
       } 
     }; 
      
     var elem = document.createElement("li");
     elem.innerHTML = "Click me!";
     elem.onclick = Button.click;
     document.getElementById("results").appendChild(elem);
    
     elem.onclick();
     test( elem.clicked, "The clicked property was accidentally set on the element" ); 
    We need to keep its context as the original object.
     function bind(context, name){ 
       return function(){ 
         return context[name].apply(context, arguments); 
       }; 
     } 
    
     var Button = { 
       click: function(){ 
         this.clicked = true; 
       } 
     }; 
      
     var elem = document.createElement("li");
     elem.innerHTML = "Click me!";
     elem.onclick = bind(Button, "click");
     document.getElementById("results").appendChild(elem);
    
     elem.onclick();
     test( Button.clicked, "The clicked property was correctly set on the object" ); 
    Add a method to all functions to allow context enforcement.
     Function.prototype.bind = function(object){ 
       var fn = this;
       return function(){ 
         return fn.apply(object, arguments);
       }; 
     }; 
    
     var Button = { 
       click: function(){ 
         this.clicked = true; 
       } 
     }; 
      
     var elem = document.createElement("li");
     elem.innerHTML = "Click me!";
     elem.onclick = Button.click.bind(Button);
     document.getElementById("results").appendChild(elem);
    
     elem.onclick();
     test( Button.clicked, "The clicked property was correctly set on the object" ); 
    Our final target (the .bind method from Prototype.js).
     Function.prototype.bind = function(){ 
       var fn = this, args = Array.prototype.slice.call(arguments), object = args.shift(); 
       return function(){ 
         return fn.apply(object, 
           args.concat(Array.prototype.slice.call(arguments))); 
       }; 
     }; 
    
     var Button = { 
       click: function(value){ 
         this.clicked = value; 
       } 
     }; 
      
     var elem = document.createElement("li");
     elem.innerHTML = "Click me!";
     elem.onclick = Button.click.bind(Button, false);
     document.getElementById("results").appendChild(elem);
    
     elem.onclick();
     test( Button.clicked === false, "The clicked property was correctly set on the object" ); 
    Bonus: Function Length
    How does a function's length property work?
     function makeNinja(name){} 
     function makeSamurai(name, rank){} 
     test( makeNinja.length == 1, "Only expecting a single argument" ); 
     test( makeSamurai.length == 2, "Multiple arguments expected" ); 
    We can use it to implement method overloading.
     function addMethod(object, name, fn){ 
       // Save a reference to the old method
       var old = object[ name ]; 
    
       // Overwrite the method with our new one
       object[ name ] = function(){ 
         // Check the number of incoming arguments,
         // compared to our overloaded function
         if ( fn.length == arguments.length ) 
           // If there was a match, run the function
           return fn.apply( this, arguments );
    
         // Otherwise, fallback to the old method
         else if ( typeof old === "function" ) 
           return old.apply( this, arguments ); 
       }; 
     } 
    How method overloading might work, using the function length property.
     function addMethod(object, name, fn){ 
       // Save a reference to the old method
       var old = object[ name ]; 
    
       // Overwrite the method with our new one
       object[ name ] = function(){ 
         // Check the number of incoming arguments,
         // compared to our overloaded function
         if ( fn.length == arguments.length ) 
           // If there was a match, run the function
           return fn.apply( this, arguments );
    
         // Otherwise, fallback to the old method
         else if ( typeof old === "function" ) 
           return old.apply( this, arguments ); 
       }; 
     } 
    
     function Ninjas(){ 
       var ninjas = [ "Dean Edwards", "Sam Stephenson", "Alex Russell" ]; 
       addMethod(this, "find", function(){ 
         return ninjas; 
       }); 
       addMethod(this, "find", function(name){ 
         var ret = []; 
         for ( var i = 0; i < ninjas.length; i++ ) 
           if ( ninjas[i].indexOf(name) == 0 ) 
             ret.push( ninjas[i] ); 
         return ret; 
       }); 
       addMethod(this, "find", function(first, last){ 
         var ret = []; 
         for ( var i = 0; i < ninjas.length; i++ ) 
           if ( ninjas[i] == (first + " " + last) ) 
             ret.push( ninjas[i] ); 
         return ret; 
       }); 
     } 
      
     var ninjas = new Ninjas(); 
     test( ninjas.find().length == 3, "Finds all ninjas" ); 
     test( ninjas.find("Sam").length == 1, "Finds ninjas by first name" ); 
     test( ninjas.find("Dean", "Edwards").length == 1, "Finds ninjas by first and last name" ); 
     test( ninjas.find("Alex", "X", "Russell") == null, "Does nothing" ); 
    Objects using JSON
     
    // Read more about JSON.org
    var obj = { foo: "test" };
    
    var menu =
    			{"menu": {
    			  "id": "file",
    			  "value": "File",
    			  "popup": {
    			    "menuitem": [
    			      {"value": "New", "onclick": "CreateNewDoc()"},
    			      {"value": "Open", "onclick": "OpenDoc()"},
    			      {"value": "Close", "onclick": "CloseDoc()"}
    			    ]
    			  }
    			}} ;
    
    // Not so usefull in this case:
    log(  obj   );
    log(  Object.getOwnPropertyDescriptor( obj, "foo" )  );
    
    // JSON very usefull
    log(  JSON.stringify(  Object.getOwnPropertyDescriptor( obj, "foo" )  ));
    
    //Show the Menu object as JSON
    log(  JSON.stringify(  Object.getOwnPropertyDescriptor( menu, "menu" )  ));	
    
    jQuery Basics
    jQuery Selectors
    	
    	/**********************************
    	 * jQuery() = $() 
    	 * Find elements with ID = results,
    	 * Add any existing CSS roles 
    	 * Apply new CSS rules 
    	 ***********************************/
    	 
    	
     	jQuery('#results').                              
     	
     	html('<h1> Hello from jQuery </h1> ').  
     	
     	addClass('Fixed_Position').
     	
     	css(
     		{	color:		'white', 
     			backgroundColor:'gray' 
     			
     		}
     	);
     	
     	log()
    
    	 
    
    jQuery Advanced
    jQuery Get remote data
    	// supermobile.dk/jQuery/xml/
    	// GET remote data from XML-file 
     
       	$.get('http://supermobile.dk/javascript/learn/Books.xml', function (d) {
                    $('#results').append('<h1> Recommended Web Development Books </h1>');
                    $('#results').append('<dl />');
    
                    $(d).find('book').each(function () {
    
                        var $book = 		$(this);
                        var title = 		$book.attr("title");
                        var description =   $book.find('description').text();
                        var imageurl = 	 $book.attr('imageurl');
    
                        var html = '<dt> <img class="bookImage" alt="" src="' + imageurl + '" /> </dt>';
                        html += '<dd> <span class="loadingPic" alt="Loading" />';
                        html += '<p class="title">' + title + '</p>';
                        html += '<p> ' + description + '</p>';
                        html += '</dd>';
    
                        $('dl').append($(html));
    
                        $('.loadingPic').fadeOut(1400);
                    });
                });
     	
     	log()
    
    	 
    
    Play with Canvas
    Hello World Canvas
     
    	// Add a Canvas to the #results HTMLelement 
    	jQuery('#results').
    	append('<canvas id="my-canvas" height="200" width="400"> </canvas>') ;
    	
    	 function draw() {
                var canvas = document.getElementById("my-canvas");
                if (canvas.getContext) {
                    var context = canvas.getContext("2d");
                    context.fillStyle = "red";
                    context.strokeStyle = "Yellow";
    
                    context.font = "italic small-caps bold 44pt 'Comic Sans MS'";
                    context.textAlign = "left";
                    context.strokeText("Hello", 10, 100);
                    context.fillText("World!", 10 + context.measureText("Hello ").width, 100);
                }
            }	
    	
    	draw();
    	
    	log();
    	
    
    
    Advanced Canvas animation
     
    	// Add a new Canvas and position 
    	jQuery('#results').
    	addClass('Fixed_Position'). 
    	append('<canvas id="my-canvas" height="400" width="400"> </canvas>');
    	
    	//Call setup to configure the Canvas
    	setup();
    		
    	var timer=null;
    
    	function setup() {
    		var canvas=document.getElementById("my-canvas");
    		var context;
    		if (canvas.getContext) {
    			context = canvas.getContext("2d");
    			context.translate(canvas.width/2,canvas.height/2);
    			context.restore();
    			draw(context,1);
    		}
    	}
    	
    	function draw(context,rotation) {
    		context.beginPath();
    		rect(context,"fill",0,0,100,100,255,0,0,1);	
    		rect(context,"fill",50,50,100,100,0,0,255,.1);	
    		rect(context,"stroke",50,50,100,100);	
    		rect(context,"clear",50,50,50,50);	
    		rect(context,"fill",50,50,50,50,102,0,102,.1);	
    		rect(context,"stroke",0,0,100,100,255,0,0);	
    		line(context,0,0,100,100);
    		line(context,100,0,150,50);
    		line(context,0,100,50,150);
    		line(context,100,100,150,150);
    		context.stroke();
    		rotate(context,rotation);
    		context.save();
    	}
    	
    	function rect(context,type,x,y,w,h,r,g,b,t) {
    		var color;
    		if (typeof t == "undefined") t=1;
    		switch (type) {
    			case "fill" :
    				color = "rgba(" + r + "," + g + "," + b + "," + t + ")";
    				context.fillStyle=color;
    				context.fillRect(x,y,w,h);
    				break;
    			case "stroke" :
    				context.strokeRect(x,y,w,h);
    				break;
    			case "clear" :
    				context.clearRect(x,y,w,h);
    				break;
    		}
    	}
    	
    	function line(context,x1,y1,x2,y2) {
    		context.moveTo(x1,y1);
    		context.lineTo(x2,y2);
    	}
    	
    	function rotate(context,i) {
    		context.rotate(-.25);
    		context.scale(1.0,.99);
    		addText();
    		timer = setTimeout(function() {draw(context,i)},10);
    	}
    	
    	function stopTimer() {
    		clearTimeout(timer);	
    	}
    	
    	function addText() {
    		var canvas=document.getElementById("my-canvas");
    		var context;
    		if (canvas.getContext) {
    			context = canvas.getContext("2d");
    			context.fillText("Hello World",10,10);	
    		}
    	}	 
    
    
    	log();