function assert(value, desc){ var res = $("#results"); var li = document.createElement("li"); li.className = value ? "pass" : "fail"; li.appendChild(document.createTextNode(desc)); res.append(li); } // every function has a name property. In case of anonymous functions its empty string assert(assert.name === "assert","Name of assert function: " + assert.name); // anonymous function var fun = function(){return this;}; assert(fun.name === "","Name of anonymous function is empty string"); // function reference var assertRef = assert; assert(assertRef.name === "assert", "Name of function still remains the same"); // There are 4 ways to invoke a function // 1 normal way - in this case the function context is window object (=this) function normalFunc(){ return this; } assert(normalFunc() === window, "function called normally, this = window"); ////////////////////// // 2 as a method on a object - in this case the function context is the calling object var car = { drive: function() {return this;} } assert(car.drive() === car, "function called as a method, this = calling object"); ////////////////////// // 3. as a constructor // constructor is just a function call done with new keyword // constructor naming convention is to have the name starting with capital letter function Person(n, dob){ this.name = n; this.dob = dob; this.age = function(){ return new Date().getYear() - dob.getYear(); }; } // 3 things happen when a constructor call happens // an empty object gets created // this object is passed to the function as function context (=this) // if no return value is provided, this object is returned var p1 = new Person("Roger Federer", new Date(1981, 08, 08)); var p2 = new Person("Sachin Tendulkar", new Date(1973, 04, 23)); assert(true, p1.name + "'s age : " + p1.age()); assert(true, p2.name + "'s age : " + p2.age()); //////////////////////// // 4. using call and apply // call and apply allow us to change the context in which the function is called // difference between call and apply is that call takes comma separated list of arguments while apply takes an array var abc = {}; var sum = 0; function callApplyDemo(arg1, arg2){ sum = arg1 + arg2; return this; } assert(callApplyDemo(4,5) === window && sum === 9, "Call Apply Demo : context is window and sum is 9"); assert(callApplyDemo.call(abc, 1,2) === abc && sum === 3, "Call Apply Demo : context is abc and sum is 3"); assert(callApplyDemo.apply(abc, [3,4]) === abc && sum === 7, "Call Apply Demo : context is abc and sum is 7"); //////////////////////// //anonymous functions are used as references var dog = {eat : function(){return "eating";}}; var cat = {eat : dog.eat}; dog = {}; // this still works because the cat.eat got a reference to anonymous function assert(true, cat.eat()); //////////////////////// // function's length property gives the number of named arguments with which the function was declared function f1(a){} function f2(a, b){} assert(f1.length === 1, "f1 has 1 named argument"); assert(f2.length === 2, "f2 has 2 named arguments"); // function's argument property gives all the arguments passed to the function // a javascript function can be called with more arguments than the function definition // the remaining arguments can be accessed via the arguments property function f3(a, b, c){ return arguments.length; } assert(f3(1,2,3,4,5) === 5, "5 arguments passed"); assert(f3(1,2) === 2, "2 arguments passed"); /////////////////////// // creating functions using Function constructor // one advantage of creating a function this way is that no closures are created var doSomething = new Function("str1", "str2", "return str1 + str2;"); assert(doSomething("Hello", " world !") === "Hello world !", "another way of declaring function works");
<div id='results'/>
body{ margin:10px; } .pass{ color:green; } .fail{ color:red; text-decoration:line-through; }