JavaScript: Anonymous functions

1:21 PM Xun 4 Comments

JavaScript can definitely look weird and convoluted, even in those code people say are just about "relatively simple concepts" and "are applied in practice quite often". For example, this little JavaScript quiz. And cherry pick one example:

 var foo = {
bar: function() { return this.baz; },
baz: 1
};
(function(){
return typeof arguments[0]();
})(foo.bar);


It sure looks weird and convoluted to me.

About half of the weird-ness about JavaScript has to do with anonymous function, the way it is created, called, passed with parameters, passed around. That said, anonymous function is definitely ubiquitous and indeed worthy of some true understanding.

Anonymous function by definition is simple. It is just a function without name (in contrast to a non-anonymous function that has a name).

Example of a non-anonymous function:

 function sayHello(){
alert("hi");
}


Example of a anonymous function:

 var sayHello = function(){
alert("hi");
};


What's the difference between the two
sayHellos
? Logically they are the same. However, the second one is an expression, an anonymous function assigned to a variable
sayHello
; The first one is a function declaration, while the second one a function expression. This causes the difference how they can be accessed.

Example of different accessibility between anonymous function and non-anonymous function:

 
// anonymous function assigned to a variable cannot be called before the variable is initialized
fnAnonymous(); // undefined

var fnAnonymous = function(){
alert("hi");
};

fnAnonymous(); //hi

// a named function can be accessed anywhere as long as it is within the same scope that the function is created
fnNamed(); // hi

function fnNamed(){
alert("hi");
};

fnNamed(); //hi

So even the above
fnAnonymous()
are
fnNamed()
are essentially the same, yet one (
fnNamed
) is created through function declaration, the other through function expression. The former (named function) is created in the scope before execution and can be assessed throughout in the same scope, while the later is created until the expression is evaluated and cannot be assessed before the line of evaluation.

Anonymous functions are created all the time, accidentally or not. They exist in different shapes and forms.

All the following involves anonymous functions:

 // function expression
var sayHello = function (){
alert("hi");
};

// in an object
var Person = {
sayHello: function(){
alert("hi");
}
};

// event handler
$("p").click = function(){
alert("hello");
};

// ajax callback from http://api.jquery.com/jQuery.ajax/
$.ajax({
url: "test.html",
context: document.body,
success: function(){
$(this).addClass("done");
}
});

//Self-evoking anonymous functions
((function () {
alert("hi");
})());


What are anonymous functions for? Benefits?

Simply, anonymous functions are used for the reasons of: a) code brevity. It often makes sense to use anonymous functions calls in callbacks and event handlers; b) scope management. Anonymous functions can be used to create temporary/private scope; c) Anonymous function are often handy in closures and recursions.

In JavaScript, scope could be tricky but it is fundamental to JavaScript understanding. And anonymous functions are often used to create a temporary / private scope.

A commonly cited example is jQuery.

 (function( window, undefined ) {

var jQuery = (function() {
});

// Expose jQuery to the global object
window.jQuery = window.$ = jQuery;

//
})(window);


The above ensures the function is called immediately; it also ensures every variable declared in the anonymous function is a private variable, therefore won't spill into and pollute the global scope, which is extremely important from a library's perspective; it also ensures that the scope chain is destroyed after the function finishes execution.


Recursions


Recursions are functions that call themselves, they are often used to solve problems such as factorials, the tower of hanoi, golden ratio (See wiki Recursion. Or, fibonacci numbers.

 function fibonacci(n) {
if (n < 2)
return n;

return fibonacci(n - 1) + fibonacci(n - 2);
}

alert(fibonacci(6)); //8


It works fine. But it can/should be improved with two things:
arguments.callee
and function memorization. As the following:

 function f(n) {

if (n < 2)
return n;

if (f.answers[n] != null)
return f.answers[n];

f.answers[n] = arguments.callee(n - 1) + arguments.callee(n - 2);

return f.answers[n];
}

f.answers ={};

var fibo = f;
alert(fibo(10)); //55
alert(fibo(11)); //89



So, first,
arguments.callee
. All functions have a pointer
arguments.callee
to itself. Using
arguments.callee
instead of the function names ensures that the function can always be accessed, even when the function is assigned to a variable; second, store the computed value in memory. Because all recursions involves doing the same calculation over and over again, we can just save some extra work and repetitions by storing the known/already computed answers.


Closures

Functions returned from another function are called closures. Closures and anonymous functions often goes hand in hand.

 $('#foo').click( function() {
alert('User clicked on "foo."');
});


Closures can often get into trouble with loops, and one sure way to get out of the loop is to use anonymous function to create a temporary scope.

So a loop like this is problematic.

 for (var i = 1; i <= 10; i++) {
$('#Div' + i).click(function () {
alert('#Div' + i + " is kicked");
return false;
});
}


Yet if you rewrite it a bit, it will work!

 for (var i = 1; i <= 10; i++) {
(function(v){
$('#Div' + v).click(function () {
alert('Div' + v + " is kicked");
return false;
})
})(i);
}


Read more about closures at JavaScript closures


Back to the weird anonymous function

Now let's go back to the weird code that sits squarely in the quiz we mentioned in the beginning.

 var foo = {
bar: function() { return this.baz; },
baz: 1
};

(function(){
return typeof arguments[0]();
})(foo.bar);



What would be the correct answer?
a) "undefined"
b) "object"
c) "number"
d) "function"

The answer is a) "undefined". I did not get this right until I ran the code. I cheated.

Brief explanation (found in the comments section):

"It’s important to understand that this is not a closure variable. Instead, it is determined at function-run-time, by the entity which it ‘belongs to’ at the time — and if there is no such object, then the object is window. So if you call foo.bar(), then this will point at foo. But when you call arguments[0](), it points at arguments instead. Since arguments.baz is undefined, you get this particular behaviour."

hmm. Takes some chewing.

A hasty conclusion

Well, there is still so much more about JavaScript anonymous function. And it could be a pain. If it is, hopefully this would alleviate your pain a bit.

So long!


Source:

Secrets of the JavaScript Ninja
Professional JavaScript for Web Developers
Javascript quiz
JavaScript closures

4 comments:

  1. So a loop like this is problematic. you say.
    but why should that be problematic? i don't understand

    ReplyDelete
  2. Mootools is a repository of all javascript libraries from intermediate to senior level. Find all the utilities here mootools .


    ReplyDelete
  3. Superb i really enjoyed very much with this article here. Really its a amazing article i had ever read. I hope it will help a lot for all. Thank you so much for this amazing posts and please keep update like this excellent article.click for more school branding uk

    ReplyDelete
  4. Great and excellent article. I got more knowledge from this article.recognition a lot for sharing this feature with usPython Online Training
    Learn Python Online

    ReplyDelete