WHAT’S WRONG WITH JAVASCRIPT?
A common feeling among many web developers on the Internet is that while Javascript (JS) is a useful language for adding ‘behavior’ to websites, implementing AJAX and some other ‘cool’ stuff — JS is nevertheless a ‘fundamentally flawed’ language and is unfortunately a ‘necessary’ evil.
In this mini series we will examine some of the reasons why some developers have this sentiment and we will make our own conclusions on whether or not JS is a flawed language. We will consider the three main areas which have contributed to this ‘fact’ about JS being flawed :
1. Hoisting,
2. ‘this’,
3. Object Orientation.
In this article we will consider ‘Hoisting’.
HOISTING: The JS ‘Hoisting’ mechanism tends to come as an unpleasant surprise to many devs coming to JS from other languages. What is ‘Hoisting’ anyway?
Confusion over ‘Hoisting’ arises because of a common misconception that JS is an interpreted language and so execution is carried out line by line. Consider the following code snippet:
someFunct();//’Hello World!’
a;//undefined
var a = ‘Who am I?’;
function someFunct() {
return ‘Hello World!’;
}
Line 1 shows a yet to be declared function with identifier ‘someFunct’ being invoked and returning a string value ‘Hello World!’, line 2 shows a yet to be declared variable with identifier ‘a’ being executed and returning ‘undefined’… it doesn’t seem right to many devs that line 2 should return ‘undefined’ while line 1 returns a value. If JS were truly an interpreted language this feeling would be completely correct and this ‘strange’ behavior would then be a flaw.
The reality is that JS is not an interpreted language but actually a compiled language which utilizes JIT (Just In Time) compilation and some sophisticated mechanisms to only compile the code micro/nano seconds before execution. Thus as a compiled language there are actually 2 phases any JS code undergoes before execution.
Phase1 is Compilation and Phase 2 is Execution.
In Phase 1, the JS Engine goes through the code and flags any function or variable declaration in that order and allocates memory space for the identifiers (in this case ‘someFunct and ‘a’). While the JS Engine doesn’t execute the function just yet, it does ‘peer’ into the function (and notes what the contents of the function body are), it then places the entire function body into the assigned memory space, next it assigns a placeholder value to any declared variable e.g. ‘a’ and that placeholder value is ‘undefined’.
In Phase 2, the Execution/Assignment phase, the JS Engine begins to make value assignments or implement code execution.
Thus with this background we can understand what actually happens in the preceding snippet as follows:
1. Phase 1, function ‘someFunct’ is allocated memory space and the function body “return ‘Hello World!’ “ is placed into the memory space, variable ‘a’ is also flagged and that variable declaration ‘var a’ is placed in memory and assigned an initial placeholder value of ‘undefined’ i.e. in memory we have ‘var a = undefined;’.
2. Phase 2, the JS Engine encounters the ‘someFunct’ identifier and checks if such an identifier exists in memory, because it does exist when it encounters the ‘ ()’ operator (JS operator for invoking a function) it simply executes the function ‘someFunct’ already placed in memory and this yields the value ‘Hello World!’.
When the JS Engine arrives at line 2, it meets the identifier ‘a’, it checks if such an identifier exists in memory and it finds it in memory, then it encounters the ‘;’ operator (JS operator signaling the end of a statement i.e. execute the code that immediately precedes the ‘;’) and the JS Engine searches for the value assigned to ‘a’ in memory… what does it find? You got it, the placeholder value ‘undefined’!
It then runs through the rest of the code, it gets to the ‘var a = ‘Who am I?’;’ line and ignores the variable declaration since it has already processed this in phase 1, however, it begins to process the value assignment i.e. “= ‘Who am I?’;” and it assigns the string value “Who am I?” to the variable identified by ‘a’ which previously had a placeholder value of ‘undefined’. Thus we have ‘a = ‘Who am I?’.
Next it encounters the function declaration and ignores it because it has processed this already in phase 1. And because there’s nothing after this, the JS Engine exits.
It is this ‘mysterious’ behavior of the JS Engine in which the 2 phase processing of the JS code happens so quickly that JS seems to be interpreted rather than JIT compiled which led to the ‘Hoisting’ tag.
But now, we know that there’s no ‘magical’ hoisting happening, rather JS is simply behaving the way it was designed to behave… very efficient in implementing JIT Compilation. If we modified the preceding code as follows..
someFunct();//’Hello World!’
a;//undefined
var a = ‘Who am I?’;
function someFunct() {
return ‘Hello World!’;
}
a;//’Who am I?’
We would then see the expected output for an assignment to the variable ‘a’. Is anything wrong with JS with respect to ‘Hoisting’? I’m sure we can confidently say ‘Not at all’. The ‘solution’ is to always declare variables and functions before using them in order to avoid confusing less knowledgeable devs e.g.
var a = ‘Who am I?’;
a;//’Who am I?’
function someFunct() {
return ‘Hello World!’;
}
someFunct();//’Hello World!’
The preceding code snippet is clear and straightforward to reason about. This should be our goal as devs, to write code that is clear and straightforward while doing the intended job.
Leave comments below, thanks for reading.