3

I am a C++ ( Qt ) developer and know JS a bit. I am not able to understand a part of below code. Can you please help me with this?

function augment(withFn) {
    var name, fn;
    for (name in window) {
        fn = window[name];

        if (typeof fn === 'function') {
    // **Not able to understand below code.**
            window[name] = (function(name, fn) {
                var args = arguments;
                return function() {
                    withFn.apply(this, args);
                    fn.apply(this, arguments);

                }
            })(name, fn);
    // **In above code I understood everything else except this last line. 
    // Why whole function is in circular bracket? Why it ends with (name, fn);
    // What is the meaning of this?
        }
    }
}

augment(function(name, fn) {
    console.log("calling " + name);
});
SunnyShah
  • 28,934
  • 30
  • 90
  • 137

5 Answers5

1

The self executed anonymous function is a common way to solve an issue with closures in a loops.

So it's practically an anonymous function that is declared and executed immediately with passed parameters.

Actually name parameter is useless there, since it's not used, but if you didn't do the trick - then only the last fn parameter would be passed as a reference.

The demonstration of the issue: http://jsfiddle.net/zerkms/nfjtn/

The solution (using the self-executing anonymous function): http://jsfiddle.net/zerkms/nfjtn/1/

zerkms
  • 249,484
  • 69
  • 436
  • 539
  • One question, what about efficiency? Wouldn't it be faster to define a function variable once and just `apply` it in each loop? – SJuan76 Oct 06 '12 at 09:22
  • I'm sure it would be faster, yes – zerkms Oct 06 '12 at 09:23
  • @zerkms, Thanks a lot for answer with examples. If possible, Please provide me your prefered link to learn these kind of JS concepts. – SunnyShah Oct 06 '12 at 09:48
  • @SunnyShah: actually I don't know any particular. Once while ago I experienced the issue - I've googled a bit about, that is. – zerkms Oct 06 '12 at 10:04
1

Well, first of all:

(function f(param) { alert(param); })("Hello world"); defines the function and immediately executes it.

function f(param) { alert("This: = " + this + ". Param=" + param); }
f.apply(window, "Hello world");

Calls the function f in the context of window (that is the function 'thinks' it belongs to the window object) with params params

function(param) return a reference to an anonymous function. That is:

var f = function(param) {...}; f("Hello world"); is similar to:

(function(param){...})("Hello world");
Artur Udod
  • 4,465
  • 1
  • 29
  • 58
1

The expression in parentheses (what you call "circular brackets") is an anonymous function. (name, fn) at the end of it means that the function should be called with those arguments, and the return value is assigned to window[name]. It's approximately equivalent to:

tempfn = function(name, fn) { /* body */ };
window[name] = tempfn(name, fn);
Barmar
  • 741,623
  • 53
  • 500
  • 612
1

Usually in C you would have the definition (and maybe declaration)

int anon(string name, void* function) {
}

and the call to the function

anon(name, function);

The part inside the circular brackets is the declaration of an anonymous function; which is immediately called with the (name, fn) parameters.

Think of it as (NOTE: may JS is a little rusty so some syntax error is possible)

 var fn2 = (function(name, fn) {
    var args = arguments;
    return function() {
      withFn.apply(this, args);
      fn.apply(this, arguments);
   });

And, in the loop

 window[name] = fn2.apply(name, fn);         
SJuan76
  • 24,532
  • 6
  • 47
  • 87
1

The problem you are trying to circumvent here is referencing name and fn in your loop afterwards. If you just did window[name] = function () { alert(name); } all your assigned functions would always use the value that name was last set to, not what it was when that particular function was defined in your loop. To get around this you create a function that is called immediately with the correct values and that way protects them in a new closure. You can read more about it in this SO-question: JavaScript closure inside loops – simple practical example

Community
  • 1
  • 1
Karl-Johan Sjögren
  • 16,544
  • 7
  • 59
  • 68