I'm trying to gain a deeper understanding of how Javascript works and the following code is bugging me:
function notInVar(a, b) {
return a + b
}
var inVar = function doesThisWork(a, b) {
return a + b
}
document.writeln('2 + 2 = ' + notInVar(2, 2));
document.writeln('3 + 3 = ' + inVar(3, 3));
document.writeln('4 + 4 = ' + doesThisWork(4, 4));
In Chrome, the first two document.writelns execute as expected, then I get "Uncaught ReferenceError: doesThisWork is not defined"
in Chrome. Why can't I call the second function by the name doesThisWork
? For that matter, where is the first function-object notInVar stored?
I'm trying to gain a deeper understanding of how Javascript works and the following code is bugging me:
function notInVar(a, b) {
return a + b
}
var inVar = function doesThisWork(a, b) {
return a + b
}
document.writeln('2 + 2 = ' + notInVar(2, 2));
document.writeln('3 + 3 = ' + inVar(3, 3));
document.writeln('4 + 4 = ' + doesThisWork(4, 4));
In Chrome, the first two document.writelns execute as expected, then I get "Uncaught ReferenceError: doesThisWork is not defined"
in Chrome. Why can't I call the second function by the name doesThisWork
? For that matter, where is the first function-object notInVar stored?
- 2 @stackErr: Seems fine. That's a named function expression. – elclanrs Commented Jul 3, 2013 at 2:33
- not sure, but I would say variable scope. – Jonathan de M. Commented Jul 3, 2013 at 2:33
- 1 This seems useful. – Marty Commented Jul 3, 2013 at 2:36
- permadi.com/tutorial/jsFunc/index.html Check this out – Jack Daniel's Commented Jul 3, 2013 at 2:36
- 1 Incidentally, it "works" in IE 'cos IE is broken. :-) The optional name should only be available inside the function, not outside. BTW, the ECMA reference is for FuncionExpression, scroll down to the part with the optional identifier and it should become clear. – RobG Commented Jul 3, 2013 at 3:09
6 Answers
Reset to default 8The second definition is called a named function expression and due to the nature of that definition, the only way you can call it by name is from inside the function body:
var inVar = function doesThisWork(a, b) {
return doesThisWork(a + b); // infinite recursion!
}
This can be used to achieve recursion inside an otherwise anonymous function, without having to use something like the Y-combinator.
Functions are objects. The variable inVar
holds a function object with a name of doesThisWork
.
inVar.name //=> "doesThisWork"
If a function has no name it is anonymous.
To call a function stored in a variable you use the variable name (the reference to that object). If you want to call the function inside the same function (for recursion) you can call it by its name, in this case doesThisWork
.
For that matter, where is the first function-object notInVar stored?
function notInVar(a, b) {
return a + b
}
Is equivalent to
var notInVar = function (a, b) {
return a + b
}
In your case, notInVar
is stored in the global scope.
then I get "Uncaught ReferenceError: doesThisWork is not defined" in Chrome
var inVar = function doesThisWork(a, b) {
return a + b
}
Is similar to
var inVar = function (a, b) {
return a + b
}
when it's accessed outside the function
You cannot access the function by doesThisWork
, but have to access it by inVar
The way you have it written, doesThisWork
is only available inside itself.
Function is a variable and the scope of the variable matters. For the second function, in the global scope, its variable name is inVar. The function name doesThisWork is inside its own scope and is not visible to the global scope. So you can only use inVar, not doesThisWork.
well there are multiple things about this:
first: the name of the function will be local, so you can call the same function from within locally only. which might trigger an infinite recursion when used, unless it is filtered like this if(doesThisWork.caller != doesThisWork) return doesThisWork(a,b);
.
second is that you are assigning a name for the function (not leaving it as an anonymous function) but local to it's container.
TL;DR => jump to the analysis for a clearer idea.
it is interesting to note the differences between function's declaration methods:
inline declaration :
var x = function fnName(){}; console.log(x.prototype); => fnName {} // but used locally to x
var x = function(){}; console.log(x.prototype); => Object {} // no local name, only global x
at parse-time/run-time declaration:
function fnName(){}; console.log(fnName.prototype); => fnName {} // global* and local name
My analysis: is that the locality here is due to the assignment as when you declare a function within function, that name will be used locally to the containing function and not outside that, the same goes for the variable that contains a function, since it contains it and it's name. still the variable that contains the function can be used in it's scope, as it is local to it's container function which is a different scope.
*global here means global to the function's location not to the document. as it is local to it's container but global to other objects in the same container.