JavaScript Function Order: Why Does It Matter

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

  1. How you define the functions and
  2. 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):

  1. A "variable object" is created for the execution context.
  2. 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's f1 and f2. Initially the properties have the value undefined.
  3. 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.
  4. The f1(); line is executed, calling the f1 function.
  5. The f1 code refers to f2, which it gets from the variable object, and so it's what we expect it to be (a reference to the f2 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:

  1. foo is created (since it's defined by a declaration).
  2. The alert runs.
  3. The setTimeout runs.
  4. (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.

  1. Javascript evaluation is from left to right.
  2. 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:

  1. Anything to the right of an = sign (or : on object literals).
  2. Anything in parentheses ().
  3. 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



Leave a reply



Submit