Learning Advanced JavaScript



Our Goal
Goal: To be able to understand this function:
// 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))); 
   }; 
 }; 
Some helper methods that we have:
assert( true, "I'll pass." );
assert( "truey", "So will I." );
assert( false, "I'll fail." );
assert( null, "So will I." );
log( "Just a simple log", "of", "values.", true );
error( "I'm an error!" );
Defining Functions
What ways can we define functions?
 function isNimble(){ return true; } 
 var canFly = function(){ return true; }; 
 window.isDeadly = function(){ return true; }; 
 log(isNimble, canFly, isDeadly); 
Does the order of function definition matter?
 var canFly = function(){ return true; }; 
 window.isDeadly = function(){ return true; }; 
 assert( isNimble() && canFly() && isDeadly(), "Still works, even though isNimble is moved." ); 
 function isNimble(){ return true; } 
Where can assignments be accessed?
 assert( typeof canFly == "undefined", "canFly doesn't get that benefit." ); 
 assert( typeof isDeadly == "undefined", "Nor does isDeadly." ); 
 var canFly = function(){ return true; }; 
 window.isDeadly = function(){ return true; }; 
Can functions be defined below return statements?
 function stealthCheck(){ 
   assert( stealth(), "We'll never get below the return, but that's OK!" ); 

   return stealth();

   function stealth(){ return true; } 
 } 

 stealthCheck(); 
Named Functions
We can refer to a function, within itself, by its name.
 function yell(n){ 
   return n > 0 ? yell(n-1) + "a" : "hiy"; 
 } 
 assert( yell(4) == "hiyaaaa", "Calling the function by itself comes naturally." ); 
What is the name of a function?
 var ninja = function myNinja(){ 
   assert( ninja == myNinja, "This function is named two things - at once!" ); 
 }; 
 ninja(); 
 assert( 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"; 
   } 
 }; 
 assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 
But what happens when we remove the original object?
 var ninja = { 
   yell: function(n){ 
     return n > 0 ? ninja.yell(n-1) + "a" : "hiy"; 
   } 
 }; 
 assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." ); 

 var samurai = { yell: ninja.yell }; 
 var ninja = null; 
  
 try { 
   samurai.yell(4); 
 } catch(e){ 
   assert( 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"; 
   } 
 }; 
 assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" ); 
  
 var samurai = { yell: ninja.yell }; 
 var ninja = {}; 
 assert( 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"; 
   } 
 }; 
 assert( ninja.yell(4) == "hiyaaaa", "arguments.callee is the function itself." ); 
Functions as Objects
How similar are functions and objects?
 var obj = {}; 
 var fn = function(){}; 
 assert( 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"; 
 assert( obj.prop == fn.prop, "Both are objects, both have the property." ); 
Is it possible to cache the return results from a function?
 function getElements( name ) {
   var results;

   if ( getElements.cache[name] ) {
     results = getElements.cache[name];
   } else {
     results = document.getElementsByTagName(name);
     getElements.cache[name] = results;
   }

   return results;
 } 
 getElements.cache = {};

 log( "Elements found: ", getElements("pre").length );
 log( "Cache found: ", getElements.cache.pre.length ); 
QUIZ: Can you cache the results of this function?
 function isPrime( num ) { 
   var prime = num != 1; // Everything but 1 can be prime 
   for ( var i = 2; i < num; i++ ) { 
     if ( num % i == 0 ) { 
       prime = false; 
       break; 
     } 
   } 
   return prime; 
 } 
  
 assert( isPrime(5), "Make sure the function works, 5 is prime." ); 
 assert( isPrime.cache[5], "Is the answer cached?" );
One possible way to cache the results:
 function isPrime( num ) { 
   if ( isPrime.cache[ num ] != null ) 
     return isPrime.cache[ num ]; 
    
   var prime = num != 1; // Everything but 1 can be prime 
   for ( var i = 2; i < num; i++ ) { 
     if ( num % i == 0 ) { 
       prime = false; 
       break; 
     } 
   }
   
   isPrime.cache[ num ] = prime
   
   return prime; 
 } 
 
 isPrime.cache = {}; 
  
 assert( isPrime(5), "Make sure the function works, 5 is prime." ); 
 assert( isPrime.cache[5], "Make sure the answer is cached." ); 
Context
What happens if a function is an object property?
 var katana = { 
   isSharp: true, 
   use: function(){ 
     this.isSharp = !this.isSharp; 
   } 
 }; 
 katana.use();
 assert( !katana.isSharp, "Verify the value of isSharp has been changed." );
What exactly does context represent?
 function katana(){ 
   this.isSharp = true; 
 } 
 katana(); 
 assert( isSharp === true, "A global object now exists with that name and value." ); 
  
 var shuriken = { 
   toss: function(){ 
     this.isSharp = true; 
   } 
 }; 
 shuriken.toss(); 
 assert( 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; 
 } 
 assert( fn() == this, "The context is the global object." ); 
 assert( 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; 
 } 
 assert( add.call(this, 1, 2) == 3, ".call() takes individual arguments" ); 
 assert( 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){ 
   assert(value == num++, "Make sure the contents are as we expect it."); 
   assert(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){ 
   assert(value == num++, "Make sure the contents are as we expect it."); 
   assert(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(); 
 assert( !ninjaA, "Is undefined, not an instance of Ninja." ); 
  
 var ninjaB = new Ninja(); 
 assert( 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(); 
 assert( ninja.swingSword(), "Calling the instance method." ); 
 assert( ninja.swung, "The ninja has swung the sword." );
 
 var ninjaB = new Ninja();
 assert( !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("John");
assert( ninja.name == "John", "The name has been set on initialization" );

ninja.changeName("Bob");
assert( 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("John");
assert( ninja.name == "John", "The name has been set on initialization" );

ninja.changeName("Bob");
assert( 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("John", "Resig"); 
 assert( 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 = "Resig"; 
 var user = User("John", name); 
  
 assert( name == "John Resig", "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 = "Resig"; 
 var user = User("John", name); 
  
 assert( user, "This was defined correctly, even if it was by mistake." ); 
 assert( name == "Resig", "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 = "Resig"; 
 var user = User("John", name); 
  
 assert( user, "This was defined correctly, even if it was by mistake." ); 
 assert( name == "Resig", "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 = "Resig"; 
 var user = User("John", name); 
  
 assert( user, "This was defined correctly, even if it was by mistake." ); 
 assert( name == "Resig", "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: "John"}, {city: "Boston"}); 
 assert( merged.name == "John", "The original name is intact." ); 
 assert( merged.city == "Boston", "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 ); 
 } 
 assert(smallest([0, 1, 2, 3]) == 0, "Locate the smallest value."); 
 assert(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 ); 
 } 
 assert(smallest(0, 1, 2, 3) == 0, "Locate the smallest value."); 
 assert(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;
   });
 } 
 assert(highest(1, 1, 2, 3)[0] == 3, "Get the highest value."); 
 assert(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]
 assert(highest(1, 1, 2, 3)[0] == 3, "Get the highest value."); 
 // Expecting: [5,4,3,2,1]
 assert(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 );
 }

 assert(highest(1, 1, 2, 3)[0] == 3, "Get the highest value."); 
 assert(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;
 } 
 assert( 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;
 } 
 assert( 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;
 }

 assert( 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;

 assert( 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 ); 
   assert( 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 { 
     assert( count == 5, "Count came via a closure, accessed each step." ); 
     assert( 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 );
 assert( 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(); 
 assert( ninja.getSlices() == 1, "We're able to access the internal slice data." ); 
 assert( 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){
  assert( a == ___, "Check the value of a." );

  function innerRun(){
    assert( b == ___, "Check the value of b." );
    assert( c == ___, "Check the value of c." );
  }

  var b = 7;
  innerRun();
  var c = 8;
}
runMe(6);

for ( var d = 0; d < 3; d++ ) {
  setTimeout(function(){
    assert( d == ___, "Check the value of d." );
  }, 100);
}
The last one is quite tricky, we'll revisit it.
var a = 5;
function runMe(a){
  assert( a == 6, "Check the value of a." );

  function innerRun(){
    assert( b == 7, "Check the value of b." );
    assert( 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(){
    assert( 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 { 
       assert( count == 5, "Count came via a closure, accessed each step." ); 
       assert( timer, "The timer reference is also via a closure." ); 
       clearInterval( timer ); 
     } 
   }, 100);
})();

assert( typeof count == "undefined", "count doesn't exist outside the wrapper" );
assert( 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 );
    assert( 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(){
     assert( 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(){
     assert( 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(); 
 assert( !ninjaA, "Is undefined, not an instance of Ninja." ); 
  
 var ninjaB = new Ninja(); 
 assert( 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(); 
 assert( 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; 
 }; 
  
 assert( ninjaA.swingSword(), "Method exists, even out of order." );
 assert( 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
  
 assert( !ninjaA.swing().swung, "Verify that the swing method exists and returns an instance." );
 assert( !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;
 }; 
  
 assert( !ninjaA.swing().swung, "Verify that the swing method exists and returns an instance." );
 assert( !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(); 

 assert( typeof ninja == "object", "However the type of the instance is still an object." );   
 assert( ninja instanceof Ninja, "The object was instantiated properly." ); 
 assert( 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(); 
  
 assert( 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 = ___;

assert( 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();

assert( 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 }; 

 assert( (new Ninja()) instanceof Person, "Will fail with bad prototype chain." );
  
 // Only this maintains the prototype chain 
 Ninja.prototype = new Person(); 
  
 var ninja = new Ninja(); 
 assert( ninja instanceof Ninja, "ninja receives functionality from the Ninja prototype" ); 
 assert( ninja instanceof Person, "... and the Person prototype" ); 
 assert( 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();
 assert( 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 = "John Resig";
 }
 Me.prototype = new Person();

 var me = new Me();
 assert( 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){ 
   assert( 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 }; 

 assert( 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();
 assert( 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();
 assert( 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();
 assert( 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();
 assert( 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){} 
 assert( makeNinja.length == 1, "Only expecting a single argument" ); 
 assert( 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(); 
 assert( ninjas.find().length == 3, "Finds all ninjas" ); 
 assert( ninjas.find("Sam").length == 1, "Finds ninjas by first name" ); 
 assert( ninjas.find("Dean", "Edwards").length == 1, "Finds ninjas by first and last name" ); 
 assert( ninjas.find("Alex", "X", "Russell") == null, "Does nothing" );