I'm guessing this is some sort of "scope" issue but I want to understand why this is the case.
function foo(){
return true;
}
function bar(){
var foo = foo();
console.log(foo);
}
var foo = foo();
console.log(foo); //returns true as expected
But when I do the following
function foo(){
return true;
}
function bar(){
var foo = foo();
console.log(foo);
}
bar(); //returns Uncaught TypeError: foo is not a function
It seems that a variable name cannot be the same as a function name. But that isn't true is it?
There are two concepts which should help you understand this:
The first is shadowing which means that if you define a variable name inside a scope, it will hide the same variable name (or function name) from a parent scope.
The second is hoisting which causes any variable declarations to be moved to the top of the local scope.
This code
function foo(){}
function bar(){
var foo = foo();
console.log(foo);
}
is equivalent to this
var foo;//will initialize foo to undefined
foo = function(){}
var bar;
bar = function(){
var foo;//will shadow parent foo and initialize foo to undefined
foo = foo(); //fails because you are trying to call an undefined object
console.log(foo);
}
Hopefully, this makes it obvious why 'foo is not a function'. Your bar function is declaring a new foo variable (which hides the global one inside the bar scope) and then tries assigning this variable by calling itself.
You can read more about the intricacies of var here:
https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/var
In JavaScript, the names created by function declarations like your foo declaration are very much the same as variables. And so your second example fails for the same reason that this example alerts 2, not 1:
var a = 1;
function bar() {
var a = 2;
alert(a);
}
...because the a inside bar shadows the a outside bar that would otherwise be in scope since bar closes over it.
It seems that a variable name cannot be the same as a function name. But that isn't true is it?
A variable name can indeed be the same as a function name, but if you do that in a nested scope (as you have), the variable name shadows the function name.
In your bar:
function bar(){
var foo = foo();
console.log(foo);
}
...the foo in foo() is the variable declared in bar, not the function declared in the outer scope. As such, it has the default value variables have (undefined), which can't be called, so you get the error.
In a comment you've asked:
Since that is the case that i'm overwriting foo in the second example, aren't I also overwriting it in the first example?
No, and that takes us back to the first statement above: The name created by a function declaration is very much like a variable. As such, if you declare a function, then later declare a variable with the same name, the variable declaration is ignored. So your first example is interpreted as though there were no var foo at all at global scope. So var foo = foo(); is really foo = foo(), which works just fine, calling foo and then using the return value to update foo. (Doing it again would fail, because the value the function returns isn't callable.)
Check the commend on the code
function foo(){
return true;
}
function bar(){
var foo = foo(); // before calling foo(), foo is defined as a variable, so foo is not a function anymore in this scope.
console.log(foo);
}
bar(); //returns Uncaught TypeError: foo is not a function
Related
var f=function foo()
{
console.log("hello");
};
f();
foo();
This produces an error as : "Exception: ReferenceError: foo is not defined"
But "foo" is defined. Why does this happen?I know that this is a function expression and "f()" is used to access this function. But this is not an anonymous function , I do have a name for this function. Why am I not able to access the function using its name?
MDN - function expression
syntax
var myFunction = function [name]([param1[, param2[, ..., paramN]]]) {
statements
};
The function name. Can be omitted, in which case the function is anonymous. The name is only local to the function body.
You are conflating function expressions with function declarations.
This declares a variable foo and assigns an anonymous function to it:
var foo = function() {};
This declares a function bar in the current scope:
function bar() {};
This declares a variable baz and assigns it a function whose name is qux:
var baz = function qux() {};
Note that in this case, the function is not being declared in this scope. Only the variable is being declared. It just so happens that the name property of this function will be set to qux.
See this question.
Edit: code blocks
Edit: added relevant link
In this example, I know that it's going to print undefined.
var bar = typeof foo;
var foo = function() {
console.log('abcd');
}
foo();
console.log(bar); // -> undefined
So I understand that when the variables are hoisted, bar remains above foo, but foo gets executed, so shouldn't the interpreter know what foo is?
Note: I'm trying to understand how the interpreter works. My question isn't about how to fix the above snippet.
If you account for the variable definition hoisting, your code is equivalent to this:
var bar;
var foo;
// foo does not yet have a value, so it it's still undefined
bar = typeof foo;
// foo gets a value here
foo = function() {
console.log('abcd');
}
// since foo got a value in the previous statement, you can now execute it here
foo();
console.log(bar);
Only the variable definitions themselves are hoisted, not the assignments.
So, you can see from this ordering that when you execute bar = typeof foo that foo does not yet have a value so thus you assign undefined to bar.
Function definitions such as:
function foo() {
console.log('abcd');
}
are also hoisted, so if you defined foo like this, then it would be a different story. But the function assignment you are using is not itself hoisted. The way you define foo, it is just a variable assignment like any other.
Original Question:
JSHint complains when my JavaScript calls a function that is defined further down the page than the call to it. However, my page is for a game, and no functions are called until the whole thing has downloaded. So why does the order functions appear in my code matter?
EDIT: I think I may have found the answer.
http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting
I am groaning inside. Looks like I need to spend ANOTHER day re-ordering six thousand lines of code. The learning curve with javascript is not steep at all, but it is very loooooong.
tl;dr If you're not calling anything until everything loads, you should be fine.
Edit: For an overview which also covers some ES6 declarations (let, const): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Scope_Cheatsheet
This weird behavior depends on
How you define the functions and
When you call them.
Here's some examples.
bar(); //This won't throw an error
function bar() {}
foo(); //This will throw an error
var foo = function() {}
bar();
function bar() {
foo(); //This will throw an error
}
var foo = function() {}
bar();
function bar() {
foo(); //This _won't_ throw an error
}
function foo() {}
function bar() {
foo(); //no error
}
var foo = function() {}
bar();
This is because of something called hoisting!
There are two ways to define functions: Function declaration and function expression. The difference is annoying and minute, so let's just say this slightly wrong thing: If you're writing it like function name() {}, it's a declaration, and when you write it like var name = function() {} (or an anonymous function assigned to a return, things like that), it's a function expression.
First, let's look at how variables are handled:
var foo = 42;
//the interpreter turns it into this:
var foo;
foo = 42;
Now, how function declarations are handled:
var foo = 42;
function bar() {}
//turns into
var foo; //Insanity! It's now at the top
function bar() {}
foo = 42;
The var statements "throws" the creation of foo to the very top, but doesn't assign the value to it yet. The function declaration comes next in line, and finally a value is assigned to foo.
And what about this?
bar();
var foo = 42;
function bar() {}
//=>
var foo;
function bar() {}
bar();
foo = 42;
Only the declaration of foo is moved to the top. The assignment comes only after the call to bar is made, where it was before all the hoisting occurred.
And finally, for conciseness:
bar();
function bar() {}
//turns to
function bar() {}
bar();
Now, what about function expressions?
var foo = function() {}
foo();
//=>
var foo;
foo = function() {}
foo();
Just like regular variables, first foo is declared at the highest point of the scope, then it is assigned a value.
Let's see why the second example throws an error.
bar();
function bar() {
foo();
}
var foo = function() {}
//=>
var foo;
function bar() {
foo();
}
bar();
foo = function() {}
As we've seen before, only the creating of foo is hoisted, the assignment comes where it appeared in the "original" (un-hoisted) code. When bar is called, it is before foo is assigned a value, so foo === undefined. Now in the function-body of bar, it's as if you're doing undefined(), which throws an error.
The main reason is probably that JSLint does only one pass on the file so it doesn't know you will define such a function.
If you used functions statement syntax
function foo(){ ... }
There is actually no difference at all where you declare the function (it always behaves as if the declaration is on the beginning).
On the other hand, if your function was set like a regular variable
var foo = function() { ... };
You have to guarantee you wont call it before the initialization (this can actually be a source of bugs).
Since reordering tons of code is complicated and can be a source of bugs in itself, I would suggest you search for a workaround. I'm pretty sure you can tell JSLint the name of global variables beforehand so it doesn't complain about undeclared stuff.
Put a comment on the beggining of the file
/*globals foo1 foo2 foo3*/
Or you can use a text box there for that. (I also think you can pass this in the arguments to the inner jslint function if you can meddle with it.)
There are way too many people pushing arbitrary rules about how JavaScript should be written. Most rules are utter rubbish.
Function hoisting is a feature in JavaScript because it is a good idea.
When you have an internal function which is often the utility of inner functions, adding it to the beginning of the outer function is an acceptable style of writing code, but it does have the drawback that you have to read through the details to get to what the outer function does.
You should stick to one principle throughout your codebase either put private functions first or last in your module or function. JSHint is good for enforcing consistency, but you should ABSOLUTELY adjust the .jshintrc to fit your needs, NOT adjust your source code to other peoples wacky coding concepts.
One coding style that you might see in the wild you should avoid because it gives you no advantages and only possible refactoring pain:
function bigProcess() {
var step1,step2;
step1();
step2();
step1 = function() {...};
step2 = function() {...};
}
This is exactly what function hoisting is there to avoid. Just learn the language and exploit its strengths.
Only function declaration are hoisted not function expression (assignment).
Here is the code I came across:
var foo=1;
function bar(){
foo=10;
return;
function foo(){}
}
bar();
alert(foo);
And the result is 1!
Just don't know why.
As far as my understanding, the first line defined a global variable 'foo' to the window object and the value is 1, then within the bar function assign the foo with 10, since there's no 'var' before foo, so the global variable 'foo' will be assigned with the value 10. Then return, the rest of the function won't be executed.
But it alerts 1.
While remove the function foo definition within the bar function, it will alert 10.
Welcome to the mysterious world of javascript hoisting :) Read this article, you will be enlightened: http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
As a short answer: to make things work in javascript like this:
hello();
function hello() {
alert('hello');
}
Javascript first moves all function declarations to the top of your code, so you can call any functions "before" it was defined. I believe the reason why foo won't change to 10 if there is the function declaration is because it behaves like var foo;. You are defining a function locally, thus when it runs foo = 10; you are just overwriting the locally defined function foo() with the value 10.
The reason it's returning 1 is because the foo=10 is inside of the function bar()
so the foo=10 is a local variable and you have to call its function for the foo variable to change
for example if you do this it will alert 10
var foo=1;
function bar(){
foo=10;
return;
alert(foo);
}
bar();
What's the difference between declaration, definition and initialization? Example:
// Is this a declaration?
var foo;
// Did I defined object in here (but it is empty)?
var foo = {};
// Now that object is initialized with some value?
var foo = {first:"number_one"};
The first example is a declaration. You have declared a variable with the identifier foo. You haven't given it a value yet, so it will be undefined:
var foo;
console.log(foo); //undefined
The second example is a declaration and an assignment. You have assigned an empty object literal to the variable with the identifier foo. As noted in the comments, this is effectively short for:
var foo;
console.log(foo); //undefined
foo = {};
console.log(foo); //Object
The third example is another declaration and another assignment. You have assigned a different object literal to foo.
Edit (see comments)
The behaviour of your code is slightly different depending on whether you intended each example to run as an independent program, or as written (one program).
If you treat is as it's written:
Because variable declarations in JavaScript are hoisted to the top of the scope in which they appear, redeclaring variables has no effect. So the first line declares a variable foo.
The second line assigns an empty object literal to foo, and the third line assigns a different object literal to foo. Both of these assignments apply to the same foo.
What effectively happens is this:
var foo;
foo = {}; //No `var` keyword
foo = {first:"number_one"}; //No `var` keyword
If you treat each line as a separate program:
The first program declares a variable named foo. It's value is undefined.
The second program declares a variable named foo, and then assigns an empty object literal to it.
The third program declares a variable named foo and then assigns an object literal with one property to it.
You got it right.
var foo; // Is this a declaration ?
Yes, you declared that there's a variable named foo, but didn't define foo (so foo is undefined).
var foo = {} // Did I defined object in here (but it is empty) ?
Yes, now you "defined" foo... it has a value, it is no longer undefined. var foo = 5 also counts as "defining" it.
var foo = {first:"number_one"} // Now that object is initialized with some value ?
You could say that it's "initialized," but that's really just semantics. "Declared" and "defined" are a bit more meaningful.
Run the code below:
var foo;
console.dir(foo);
var foo = {};
console.dir(foo);
var foo = {first:"number_one"};
console.dir(foo);
When you declare a variable with var foo; you actually ensure that it will belong to the scope where you've defined it. What you call definition and initialization is in fact a value assignment.
Consider following piece of code as an example:
(function () {
// definition
var foo;
function assignFoo(x) {
// assignment
foo = x;
}
assignFoo(5);
console.log(foo);
})();
To say, you're not always supposed to assign value within the scope of definition. But it is the most common use case which is usually accomplished with var foo = 5.
Thats it.