Advanced JavaScript
JS Engine
Javascript is an interpreted language.
What is this engine that we speak of well ?
If I write some code like let’s say cost isHappy equals to true Well we just wrote some javascript
Now how do we read this or how does the computer read this ?
1 | const isHappy = true |
JS => engine => computer
Who created the first Javsscript Engine ?
Brendan Eich. => SpiderMonkey which is what Firefox still
inside of V8 Engine
It looks something like this we give it a js file and first is does something called lexical analysis which breaks the code into something called tokens to identify their meaning. So that we into know what the code is trying to do and these tokens are formed into what wo call an AST that is an abstract syntax tree. So we pass the code that is we try and figure out how the text is divided up based on Keywords from js and it gets formed into this tree like structure called abstract syntax tree. In once in this form it goes through something called an interpreter profiler compiler and we get some. Code that are CPU you on our computers is going to understand to give it instructions and you can think of this whole process again which we’re going to talk about in more detail coming up as something like this.
1 | function jsengine(code) { |
What problem do u see with everybody creating their own engines in js ?
V8 is an ECMAScript engine
interpreters and compilers
In programming there are generally two ways of translating to machine language or something that our computers can understand and we’re going to talk about here actually applies to most programming languages not just JS Python Java C++ any language u can think of is going to use some of these concepts. So it’s very important let’s start with the first one the interpreter. With an interpreter, what we do is we translate and read the files line by line on the fly. Let’s have a look at how this work.
1 | function sum(a, b) { |
If we give this file to an interpreter the translation happens line by line on the fly and this is how u think the code should be run right? Because interpreting code simply means taking a set of instructions like we have over here and returning an answer and doing something with that code.
But what about a compiler?
A compiler I like an interpreter doesn’t translate on the fly. What it does is it works ahead of time to create a translation of what code we’ve just written and it compiles down to usually a language that can be understood by our machines.
You see the definition itself is actually a little bit fuzzy in some respects all languages have to be interpreted and compiled because it has to run it has to be interpreted and it also has to most likely get translated into something low level like machine code for example.
1 | // JS |
First, interpreters are quick to get up and running right because if we go to our example with an interpreter We don’t have to convert this into an another language like language X like I showed.
But there’s a con with using an interpreter and this is same problem that Google had back in to day when they had Google Maps running. a lot of js but it’ll get slower and slower and slower because the problem with interpreter is that when you’re running the same code more than once. For example if you’re in a loop like this one over here where we’re running this piece of code over and over even though it gives us the same result it can get really really slow the complier actually helps us here. It takes a little bit more time to start up because it has to go through that compilation step at the beginning go through our code understand it and spit it out into a another language but the complier will be smart enough that when it sees code like this and this is obviously a simplified version of it but if he sees code like this that we just loop over and it has the same inputs returning the same outputs. Well it can actually just simplified this code and instead of calling this function multiple timers can just replace this function with something like nine because we know that we want to return nine because a compiler doesn’t need to repeat the translation for each pass through in that loop the code generated from it is actually faster and these sort of edits that compliers do are called optimization
so let’s go back to that question interpreter or complier which one is better.
They both have their pros and cons complier obviously takes a little bit longer to get up and running but the code is going to eventually run faster, interpreter that is really fast to get up and running but unfortunately doesn’t do any optimizations.
Is there a way that we can get the best of both worlds and this is what some engineers came up with in late 2000 and if we use Google as our example with the V8 engine what if we combine the best of both ?
JIT compiler or just in timer Compiler and this is exactly what browser started doing browsers started mixing compliers specifically these JIT compilers for just in time compiler to make the engines faster. So let’s see how V8 engine does this.
This old man that’s checking out our code in this profiler also called a monitor, monitors and watches our code as it runs and makes notes on how we can optimize this code sch as how many times it is being run. What types are used and how we can possibly optimize this and using this profiler as the code is running through our interpreter which tells our browser what to do if the same lines of code are run a few times. We actually pass off some of this code to the compiler or a JIT compiler adjust in time compiler because as the code is running, the interpreter is going to say here’s some code for u to optimize passes it off to the compiler and the compiler as the application is running takes a code and compiled it or modifies it.
the compiler is imperfect it can make mistakes and it can try to optimize code that actually does the opposite. And if it makes a mistake and it does something unexpected it does something called D optimization which takes even longer time to reverted back to the interpreter.
compare with other languages
.exe mostly be created by C++.
Is Js an interpreted language ?
not technically, technically it depends on the implementation.
In order to help the js engine we want to be really really careful with these on the left:
- eval()
- arguments
- for in (keys instance of)
- with
- delete
- inline-caching
- hidden classes
1 | // inline-caching |
Why not just use machine code from the beginning ?
You see if javascript were compile then either compilation would have to be super fast because remember. our js files get send from the server to the browser. So the compiling has to happen on the browser or the competing browsers that is Firefox.
WebAssembly
We have the standard binary executable format called WebAssembly and this is what we didn’t have in nineteen ninety five we didn’t have the competing browsers agreeing on this format where we can compiler code all the way down to WebAssembly. This exectable format so that it runs really fast on the browser instead of having to go through that entire js engine proess.
Call Stack and Memory Heap
Call Stack => first in last out
(anonymous) => global anonymous function
garbage collection
js automatically frees up this memory that we no longer use and will collect out garbage.
Mark and sweep
keep in mind that the execution of the loop also aided in the crash
memory leaks are pieces of memory that the application have used in the past but it’s not needed any longer but has not yet been returned back to us to the poor free memory.
1 | global variale |
JS Runtime
when Call Stack meet Web API(like setimeout, fetch) , I’m going to just send it off to the web API so this gets moved away from the call Stack and gets send to the Web API.
Execution Context
this => window(Global Object)
Hoisting
1 | var favouriteFood = 'grapes'; |
1 | 'use strict' |
Block scope
1 | if (2 > 1) { |
1 | function loop() { |
this Keyword
this
is the object that the function is a property of.
1 | function a() { |
1 | // 1. gives methods acess to their object |
1 | const a = function () { |
1 | const obj = { |
call, apply, bind
1 | const wizard = { |
1 | function multiply(a, b) { |
Type Coercion
1 | Object.is(+0, -0) // false |
First class Citizens
1 | var stuff = function() {} |
HOF
Higher order function are simply a function that can take a function as an argument or a function that returns a function.
Closure
We have these things called closures in Js because of two things that we get. One is the fact that in Js function are a first citizen. We can pass functions around like data like any other type in Js. We alse have this idea of lexical scope that is the Js engine knows based on where our code is written we even run the code. Each function has access to and closure is simply that a combination of function and the lexical environment from which it was declared. Closures allow a function to access variables from an enclosing scope or environment even after it leaves the scope in which it was declared.
1 | function a() { |
Js engine is going to keep any thing that’s still being referenced
1 | function callMe() { |
1 | // Memory efficient |
1 | // Encapsulation |
Prototype
1 | let dragon = { |
1 | let human = { |
1 | typeof Function |