This is a common question in technical interviews, and it is also a hot question among nerds like me and you.
To understand this tricky question, I will explain some other terms throughout this blog to give an overall understanding of the topic to enable the cool nerds like me and you to see it from every angle, so let's begin.
JavaScript is a high-level language, so in order for it to be understood by our machines, it has to be transformed and translated to a low-level language known as bytecode so that our computers can do the job we want them to do, like reading a file on our hard disk or surf the web and go to markmaksi.com.
So how is JavaScript transformed into this low-level bytecode? JavaScript Engines to the rescue!
The JavaScript Engine
V8 is a JavaScript Engine developed by Google. It is not the only JS Engine out there, but it is the fastest so far. While everyone can create their own engine, there are standards known as ECMAScript that every engine creator must conform to. So you can imagine how every big tech company is trying to create the fastest Engine so that more people use their web browsers so they sell more ads. V8 is now the dominant player in the market!
Wait a second.. what does JavaScript Engines have to do with web browsers? Well, all the power of web browsers and web applications we have now is because of the power of JavaScript Engines that these browsers are built upon that can understand our React.js and Vue.js and Angular code and do all the crazy features of our web applications.
So you might ask yourself, are JavaScript Engines implemented only inside web browsers? The short answer is no. The long answer? I will keep that for another blog post.
So we now know that JavaScript is translated using a JavaScript Engine, but what's inside this engine that enables it to translate our code to bytecode?
Interpreters vs. Compilers
In the world of programming, there are two ways to do that: either through an interpreter or a compiler. So what's the difference?
An interpreter translates your code and executes it line by line, so it's very quick to start. A compiler on the other hand, first translates your entire code and then executes it, so it is slower than the interpreter.
Examples of known compilers
If you read this blog I can assume you heard of Babel and TypeScript.. they are 2 examples of compilers aka. they translate one language to another to be executed later. Babel transforms modern JavaScript syntax into older and browser-compatible syntax to be supported on all browsers. TypeScript is a superset of JavaScript and it has a compiler known as tsc
that compiles and translates TypeScript to JavaScript. That's it!
So it is always better to build an engine with an interpreter than with a compiler? Not really. While interpreters are faster to launch than compilers, they cannot perform any optimization in executing the code. Imagine you have a loop that always does the exact same thing for X number of times. In that case, the compiler would optimize the execution by caching the output of the loop so it will execute very fast, while the interpreter will run the code again and again with zero optimization, which will eventually make it slower than the compiler.
JIT Compilers
The great and mighty V8 Engine has both the interpreter and the compiler in its implementation into what is known as a JIT Compiler (Just In Time Compiler). That way, it can get the best of both worlds!
JavaScript is not alone in implementing a JIT compiler in its engine. Python, Java, Rust, Ruby all use JIT compilation in a similar way.
So now you know it, the next time someone asks you if JavaScript is an interpreted language.. the answer is: not really!
Why knowing what compiler is inside V8 matters?
There are several keywords in JavaScript that are bad for the compiler and they can affect the optimization process negatively. These kewords are:
eval()
arguments
for in
to iterate over object keyswith
delete
Well to be honest, you won't face these keywords out in the wild too much other than for in
that is used to iterate over an object's keys. But knowing these keywords won't hurt, right?
Anyway, to iterate over an object keys without confusing the compiler, simply use: Object.keys()
instead. Example is below:
That's it for compiler vs. interpreter and how to write compiler-friendly code with no confusion! Have any questions? Drop them in the comments section below.