Understanding Javascript at a low level
2019-10-15
Did you ever ask yourself how Javascript works under the hood? It's important to understand how the language we're working with works on a lower level.
Top level view of the Javascript engine
- Receive source code
- Parse the code and produce an Abstract Syntax Tree (AST)
- Interpret as byte code and execute it
- The profiler checks for optimisations at run-time
- The compiler creates optimized code and replaces it with the byte code
What does the parser do?
A parser takes the source code and creates an AST.
First, the parser splits the source code into tokens. There are different kinds of tokens, e.g. let
and new
are keywords, while +
is an operator.
The tokens are then used to build the AST.
If something unexpected is found, a SyntaxError
is thrown.
A
SyntaxError
is thrown when the Javascript engine finds a piece of codes that don't belong to the language syntax.
Example
Let's try out the parser (using this website).
> var answer = 6 * 7;
[
{
"type": "Keyword",
"value": "var"
},
{
"type": "Identifier",
"value": "answer"
},
{
"type": "Punctuator",
"value": "="
},
{
"type": "Numeric",
"value": "6"
},
{
"type": "Punctuator",
"value": "*"
},
{
"type": "Numeric",
"value": "7"
},
{
"type": "Punctuator",
"value": ";"
}
]
Abstract Syntax Tree (AST)
It's a graph (data structure) that represents a program.
It's used in:
- Javascript Engine
- Bundlers: Webpack, Rollup, Parcel
- Transpilers: Babel
- Linters: ESLint, Prettify
- Type Checkers: Typescript, Flow
- Syntax Highlighters
You can check the generated AST in the AST Explorer.
Below is an example on how to add an ESLint rule.
export default function(context) {
return {
VariableDeclaration(node) {
// const variable type
if (node.kind === "const") {
const declaration = node.declarations[0];
// make sure that the value it's a number
if (typeof declaration.init.value === "number") {
if (declaration.id.name !== declaration.id.name.toUpperCase()) {
context.report({
node: declaration.id,
message: "The constant name should be in uppercase",
fix: function(fixer) {
return fixer.replaceText(declaration.id, declaration.id.name.toUpperCase())
}
})
}
}
}
}
};
};