JavaScript function order: why does it matter?
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.
When does function order matter?
I think the problem is not the order, but that the $(document).ready is executed before the js content is returned, so the function hasn't been loaded yet when it gets called.
The document ready is intended to guarantee the DOM is prepared, not that all the http calls are completed and I'm fairly certain that the usual script blocking doesn't apply in this case.
For what it's worth, I recreated your test and ran it successfully, proving the order doesn't matter and that this is a timing/loading issue: http://havenshade.com/tmp/testalert.html
I didn't find a happy solution though :(
Does function declaration order matter in ES6?
This has to do with ECMAScript's way of evaluation and initialization. In your first snippet, where todoApp
shows up before the other functions:
export const todoApp = (state = {}, action) => {
return {
todos: todos(state.todos, action),
visibilityFilter: visibilityFilter(state.visibilityFilter, action),
}
}
The reason why this does not throw a ReferenceError is because the return value is evaluated after todos
and visibilityFilter
is defined. This is described in the ECMAScript 2018 Specification:
9.2.12 FunctionDeclarationInstantiation ( func, argumentsList )
NOTE 1 [...] All other bindings are initialized during evaluation of the function body.
Here, the specification notes that when FunctionDeclarationInstantiation is called (which is called when you create a new function such as todoApp
, the bindings (such as variables or return values) are evaluated during the evaluation of the function body. This implies that the function body is not evaluated when the function is created thus the return value object is not known to contain a reference to todos
or visibilityFilter
which does not exist yet. This is is also reinforced in Object Initializers:
12.2.6 Object Initializer
NOTE 1 An object initializer is an expression describing the initialization of an Object, written in a form resembling a literal. It is a list of zero or more pairs of property keys and associated values, enclosed in curly brackets. The values need not be literals; they are evaluated each time the object initializer is evaluated.
The last line mentions that the values of an object are not evaluated until the object itself is evaluated.
Thus, since the return value of todoApp
is not evaluated until you actually call todoApp
, and object values are not evaluated until the return value is evaluated, no ReferenceError is reported because the todos
and visibilityFilter
references are not evaluated.
On the contrary, your second example is evaluated before todos
and visibilityFilter
are defined:
export const todoApp = combineReducers({
todos: todos,
visibilityFilter: visibilityFilter,
});
Here, combineReducers
is a function call. Because todos
and visibilityFilter
are function expressions, they are not hoisted, thus the combineReducers
call is evaluated before they exist. The object initializer is evaluated because it's an argument to combineReducers
, and once the initializer is evaluated, the values are evaluated. The reference to todos
and visibilityFilter
give a ReferenceError because they do not exist yet.
This also explains the third example as it works because combineReducers
is called after todos
and visibilityFilter
are defined. Your final attempt at putting todosApp
between todos
and visibilityFilter
raises another ReferenceError because todos
will be evaluated and exist but visibilityFilter
will not because it is not hoisted.
Are functions defined regardless of the order?
This behaviour of JavaScript is called hoisting. There is a good explanation on the MDN (https://developer.mozilla.org/en-US/docs/Glossary/Hoisting)
In JavaScript, functions and variables are hoisted. Hoisting is JavaScript's behavior of moving declarations to the top of a scope (the global scope or the current function scope).
That means that you are able to use a function or a variable before it has been declared, or in other words: a function or variable can be declared after it has been used already.
Basically, if you declare a variable like this:
console.log(s); // s === undefined
var s = 'some string';
s
declaration will be "hoisted" to the beginning of the scope (i.e. there will be no ReferenceError
on the line with console.log
). The variable's value will not be defined at that moment though.
The same goes with assigning an anonymous function to a variable, so:
console.log(f); // f === undefined
f(); // TypeError: f is not a function
var f = function () {}; // assigning an anonymous function as a value
f(); // ok, now it is a function ;)
The variable will be hoisted and thus visible in the entire scope, but it's value, even if it's a function, will still be undefined - hence the error if you try to execute it.
On the other hand if you declare a named function:
console.log(f); // f === function f()
f(); // we can already run it
function f() {}; // named function declaration
It's definition will also be hoisted so you can run it even in the first line of the scope you've declared it.
Order of functions in JavaScript
Function declarations are processed upon entry into an executable context (e.g., the global context, or a function call), prior to any of the step-by-step code in the context being processed.
So in your code, these things happen (in this order):
- A "variable object" is created for the execution context.
- Entries (actually, literally, properties) on the "variable object" are created for every
var
and function declaration in the context (plus a few other things). In your case, that'sf1
andf2
. Initially the properties have the valueundefined
. - All function declarations are processed, and so:
- The
f1
function is defined and assigned to its property on the variable object. - The
f2
function is defined and assigned to its property on the variable object.
- The
- The
f1();
line is executed, calling thef1
function. - The
f1
code refers tof2
, which it gets from the variable object, and so it's what we expect it to be (a reference to thef2
function).
The more interesting version is this:
f1();
function f1(){var a = 1; f2();}
function f2(){return a;}
...which happens in exactly the same order listed above, because both of the declarations are handled before the first line of step-by-step code.
Function declarations are different from function expressions, which just like any other expression are evaluated when they're reached in the step-by-step execution of the code. A function expression is any time you create a function and use it as a right-hand value, e.g., assign the result to a variable or pass it into another function. Like this:
var f2 = function() {
};
or this
setTimeout(function() {
alert("Hi there");
}, 1000);
Note that we're using the result of the function
statement as the right-hand value (in an assignment, or by passing it into a function). Those are not pre-processed upon entry into an execution context (e.g., not at Step 3 above), they're handled when the flow of code reaches them. Which leads to:
f1();
function f1(){var a = 1; f2();}
var f2 = function(){return a;};
...which fails, because f2
is undefined as of when it's called.
You can use a declared function's value as a right-hand value without turning it into a function expression (we do that all the time), so long as you do it in two separate statements. So:
alert("Beginning");
function foo() { ... }
setTimeout(foo, 100);
That happens in this order:
foo
is created (since it's defined by a declaration).- The
alert
runs. - The
setTimeout
runs. - (Later)
foo
is called.
One last point: Although they should work, a function expression that includes a function name does not work reliably on all implementations and must, for now, be avoided:
var f = function foo() { ... }; // <== DON'T DO THIS
Or
setTimeout(function foo() { // <== DON'T DO THIS
}, 1000);
Internet Explorer, in particular, has issues with those, and other implementations have at various times as well.
More to explore:
- Poor misunderstood
var
- Closures are not complicated (because it talks about variable objects and how symbols are resolved)
- Anonymouses anonymous (talks more about named function expressions)
Is the function order guaranteed?
b should have been called sooner, but it waited until the function a
completed.
No. b
should be called after your synchronous code has executed because that's when a function passed to setTimeout
is called.
Callback function of setTimeout
is scheduled to run after the delay you specify as a second argument to setTimeout
. This delay is the minimum amount of time it will take to run the callback function scheduled using setTimeout
.
Once the timer expires, that callback function is put in a task queue and from there it is pushed to the call stack BUT it is only pushed once the call stack is empty.
In your case, call stack will be empty when your script has finished its execution.
I know js uses only one thread, but the processor could have switched
between executing a and b during a's execution
That's not possible with only 1 thread. In Javascript, only one thing executes at a given time, unless you use another thread.
Does the processor always execute only one function at a time (if
there is no await inside)
Yes. Even with await
, function is paused until the promise is settled. Once the promise settles, that function continues execution and at that time, nothing else executes.
Edit
notice how x becomes NaN, since b is executed during a
No, there is no interference here. Function a
is executed synchronously until the following statement
await sleep(1000);
While the function a
is paused, waiting for the promise returned by sleep(...)
to settle, during this time, function b
is executed because its timer has expired and the call stack is empty.
Since both functions assign to same variable x
, value of x
is NaN
because its value before function a
resumes is undefined
and performing addition on undefined
leads to NaN
.
Does the order of the comparison conditions matter when using OR operators in an IF function?
You need to keep two things in mind.
- Javascript evaluation is from left to right.
- The OR
||
operator is short circuiting. Which means the first time it encounters a true expression it "short-circuits" i.e. bypasses all other expressions and just returns a true. This is basic boolean algebra.
In regards to your doubt about the TypeError: Cannot read property 'length' of undefined
, either of maze[row]
or maze
is undefined. On running your snippet it turns out to be that maze[row]
is the culprit here. This might be because since you do a row-1
, in your code row might become negative causing maze[row]
to be undefined.
If you turn the order to
if (row < 0 || col < 0 || col === maze[row].length || row === maze.length) {
return
}
whenever row < 0
i.e negative the OR operation short circuits all the other expressions. Hence maze[row].length
is never evaluated and no undefined behaviour is encountered.
Does order of functions and objects really matter in Angular JS file containing module?
How to fix it
That happens because you're missing all the semicolons after the variable declarations. If you add them, it works fine. AngularJs has nothing to do with it.
In the first case it works, because the JavaScript parser of Chrome notices that the next term after the object initializer for student
is var
, which could only stand at the beginning of a statement, so it assumes that it is a new statement and inserts the semicolon for you thanks to automatic semicolon insertion.
But it can't do that in your second example, because the (
after the object initializer is valid and looks like the beginning ()
operator that does a function call, expecting what's in front of it to be a function reference. So you need the semicolon, it can't be inserted for you:
var app = angular.module('store',[]); // [] is for dependencies which we don't have yet so it's empty
(function(){
app.controller('StoreController',function(){
this.blabla = student;
});
})();
var student =
{
name:"Abc Def",
rollNumber:12,
isBrilliant: true,
isMale:false,
isFemale: false
}; // <======================= here
(function(){
app.controller('ControllerForArrayOfStudents',function(){
this.students = student1;
});
})();
var student1 = [
{
name:"Abc Def",
rollNumber:12,
},
{
name:"Ghi",
rollNumber:13,
}
];
About automatic semicolon insertion (ASI)
The standard declares that JavaScript interpretes must insert semicolons in the token stream in certain situations, where the syntax is somewhat clear and a newline is involved. (Automatic semicolon insertion)
In the first snippet all the missing semicolons are in those special cases, as they do not form a valid grammar without semicolons, so they are inserted. (The statement cannot continue with another var
, or an eof)
In the second one, the following token is a (
, which is allowed by some production of the grammar, and is not a restricted production.
Specifically it is a CallExpression
, of the first form, as an ObjectLiteral
is a MemberExpression
, as stated in the syntactic grammar.
P.S.: Moral of the story: use semicolons. Semicolons introduce redundancy in the grammar, and programming languages need a healthy level of redundancy in order to be able to notice typos. A language with no redundancy would mean that any random sequence of characters would be a valid code.
JavaScript function declaration and evaluation order
This is neither a scope problem nor is it a closure problem. The problem is in understanding between declarations and expressions.
JavaScript code, since even Netscape's first version of JavaScript and Microsoft's first copy of it, is processed in two phases:
Phase 1: compilation - in this phase the code is compiled into a syntax tree (and bytecode or binary depending on the engine).
Phase 2: execution - the parsed code is then interpreted.
The syntax for function declaration is:
function name (arguments) {code}
Arguments are of course optional (code is optional as well but what's the point of that?).
But JavaScript also allows you to create functions using expressions. The syntax for function expressions are similar to function declarations except that they are written in expression context. And expressions are:
- Anything to the right of an
=
sign (or:
on object literals). - Anything in parentheses
()
. - Parameters to functions (this is actually already covered by 2).
Expressions unlike declarations are processed in the execution phase rather than the compilation phase. And because of this the order of expressions matter.
So, to clarify:
// 1
(function() {
setTimeout(someFunction, 10);
var someFunction = function() { alert('here1'); };
})();
Phase 1: compilation. The compiler sees that the variable someFunction
is defined so it creates it. By default all variables created have the value of undefined. Note that the compiler cannot assign values yet at this point because the values may need the interpreter to execute some code to return a value to assign. And at this stage we are not yet executing code.
Phase 2: execution. The interpreter sees you want to pass the variable someFunction
to setTimeout. And so it does. Unfortunately the current value of someFunction
is undefined.
// 2
(function() {
setTimeout(someFunction, 10);
function someFunction() { alert('here2'); }
})();
Phase 1: compilation. The compiler sees you are declaring a function with the name someFunction and so it creates it.
Phase 2: The interpreter sees you want to pass someFunction
to the setTimeout. And so it does. The current value of someFunction
is its compiled function declaration.
// 3
(function() {
setTimeout(function() { someFunction(); }, 10);
var someFunction = function() { alert('here3'); };
})();
Phase 1: compilation. The compiler sees you have declared a variable someFunction
and creates it. As before, its value is undefined.
Phase 2: execution. The interpreter passes an anonymous function to setTimeout to be executed later. In this function it sees you're using the variable someFunction
so it creates a closure to the variable. At this point the value of someFunction
is still undefined. Then it sees you assigning a function to someFunction
. At this point the value of someFunction
is no longer undefined. 1/100th of a second later the setTimeout triggers and the someFunction is called. Since its value is no longer undefined it works.
Case 4 is really another version of case 2 with a bit of case 3 thrown in. At the point someFunction
is passed to setTimeout it already exists due to it being declared.
Additional clarification:
You may wonder why setTimeout(someFunction, 10)
doesn't create a closure between the local copy of someFunction and the one passed to setTimeout. The answer to that is that function arguments in JavaScript are always, always passed by value if they are numbers or strings or by reference for everything else. So setTimeout does not actually get the variable someFunction passed to it (which would have meant a closure being created) but rather only gets the object that someFunction refers to (which in this case is a function). This is the most widely used mechanism in JavaScript for breaking closures (for example in loops) before the invention of the let
keyword.
Related Topics
How to Make API Call with Hooks in React
Uncaught Typeerror: Cannot Read Property 'Value' of Null
What Is Difference Between Axios and Fetch
Access Object Properties Within Object
Best Practice for Using Window.Onload
Angular2 Dynamic Input Field Lose Focus When Input Changes
Is There a Sleep Function in JavaScript
Iterate Over Object Literal Values
Accessing an Object's Property from an Event Listener Call in JavaScript
Jquery Difference Between Change and Click Event of Checkbox
Fastest Way to Check a String Contain Another Substring in JavaScript
Using Jquery to Find an Element at a Particular Position
Get Loop Counter/Index Using For…Of Syntax in JavaScript
How to Implement Cross Domain Url Access from an Iframe Using JavaScript
Can You Force Vue.Js to Reload/Re-Render
Search Recursively for Value in Object by Property Name