
Question:
I believed at first look both self invoking function is same only difference between them is in first one I am passing callback function and then executing by arguments object while in second doing same thing by making function self invoking. Now come to points of accessing parent variable in first one example name is "undefined
" while in second one example it's accessible and giving output "Nishant
" I am not able to figure out how It's working!!
(function(){
var name = "Nishant";
arguments[0]();
})(function(){console.log(name);});
<strong>Output: (an empty string)</strong>
(function(){
var name = "Nishant";
(function(){console.log(name);})()
})();
<strong>Output: Nishant</strong>
Answer1:<blockquote>
I am not able to figure out how It's working!!
</blockquote>JavaScript has <a href="https://en.wikipedia.org/wiki/Scope_%28computer_science%29#Lexical_scoping" rel="nofollow"><strong>lexical</strong> scope</a>. That means the scope is determined by where the functions are defined inside the source code (unlike <em>dynamic scope</em>, where the scope is determined when the functions are called at runtime).
Lets add some names to your functions so we can reference them more easily:
(function foo(){
var name = "Nishant";
arguments[0]();
})(function bar(){console.log(name);});
In this case bar
is defined <em>outside</em> of foo
and hence cannot have access to the variable defined inside of foo
. In fact, at the moment bar
is created, the variable name
inside foo
doesn't even exist yet, since foo
hasn't been executed yet.<br />
Maybe it's easier to see when you do not inline the definition:
function bar(){console.log(name);}
(function foo(){
var name = "Nishant";
arguments[0]();
})(bar);
This might look more familiar, and I bet you wouldn't expect that name
inside bar
has anything to do with name
inside foo
, right?
In the other case,
(function foo(){
var name = "Nishant";
(function bar(){console.log(name);})()
})();
you defined bar
<em>inside</em> of foo
. name
is also inside foo
and hence bar
has access to that variable (lexical scope + closure).
the "name" in the first version refers the global window.name
property*, and in the second example to the private var name through the closure. The window.name
property is optional and defaults to an empty string.
If this property wouldn't happen to exist your first example would throw a reference error.
The closure is created at the scope a function was declared, not at the point it got called and in the first example the function was declared inside the global scope, in the second inside the wrapper function scope.
window.name = "NoClosure";
(function(){
var name = "Closure";
arguments[0]();
})(function(){console.log(name);}); //>"NoClosure"
window.name = "NoClosure";
(function(){
var name = "Closure";
(function(){console.log(name);})(); //>"Closure"
})();
If you inspect the of the callback with console.dir()
, you can see that it has no closure, here a snippet if you want to test it yourself.
(function wrapper(){
var isPrivate = "A closure could see me";
console.dir(arguments[0]);
})(function callback(){});
Here is another experimental setup with 2 closures showing that function declared inside a call to a function are capable of getting a closure, but it will always be the closure of the scope of the function <strong>passing</strong> it, it can not access the scope of the function it was <strong>passed to</strong> as an argument and that later calls it as a callback.
(function outerScope(){
var outerVar = "in outer scope";
(function innerScope(cb){
var innerVar = "in inner scope";
cb();
})(function callback(){
console.log(
"outer:"+ typeof outerVar,
"inner:"+ typeof innerVar);
console.dir(arguments.callee);
})
})()
*source <a href="https://developer.mozilla.org/en-US/docs/Web/API/Window.name" rel="nofollow">https://developer.mozilla.org/en-US/docs/Web/API/Window.name</a>