- Anthony Alicea, follow him on Twitter
- Javascript Basics
- JavaScript: Understanding the Weird Parts in 35ish minutes - Introduction
- Willingness to learn
- 35 min
Syntax parser
- A program that reads your code and determines what it does and if it’s grammar is valid. (Converts js into something which a computer can understand). Execution context (A wrapper to help, manage the code that is running)
- There are lots of lexical env. Which one is currently running is managed by the execution context. It contains things beyond what you have written in your code.
- Lexical Environments (Where something sits physically in the code you write) - Having to do with words or grammar. A lexical env exists in programming languages in which where you write something is important.
Global object - window
/this
- In global env,
this
refers to window.
Name/Value pair - A name that maps to unique value.
Example - const address = {street: ‘100 Main st’}
Objects - Collection of Name/Value pairs
- Whenever the js code is executed, It runs inside an execution context(wrapper)
- Base execution context is the global execution context, Global execution context contains a global object and a special variable “this” (Window object). These are created by javascript engine.
- It’s inside the lexical environment.
- Open the console and write “this” to verify the window object. Even if the code is empty an execution context is created by the javascript engine. Type “window” and it the same object as “this”. This is the global object. It will not be available on node.js server, it will contain a different global object.
- There will be a global object if you are running javascript.
- Global Object(window) = this
- Global is not inside a function
- In javascript when you create var and function and you are not inside the function those var and functions are attached to the global object. At the base level when you are not inside the function there is a global object which a javascript engine creates for you as a part of that execution context.
- The environment outside the function is the outer environment.
Example 1
var a = “hello”;
function b() {
console.log(“called b!”);
}
b(); //called b!
console.log(a); // hello
Example 2 (Moving function calls on top)
b(); //called b!
console.log(a); //undefined {This phenomenon is called Hoisting}
var a = “hello”;
function b(){
console.log(“called b!”);
}
In most programming languages, you will get an exception. Because programming languages execute their code line by line and since we haven't gotten to the function b, I can’t use it yet. That’s what we normally expect. But in javascript, it ran the function and instead of throwing an error it gave me a value - undefined. So even though the function was below but got executed
Example 3 (Remove variable)
console.log(a); //Error : a is not defined
As per web, Hoisting - Functions in javascript are moved to the top by the js engine. As if the are physically moved to the top. So that they work, no matter where you put them. But variables are also declared not initialized.
Actually -
- The execution context is created in two phases.
- The first phase is called the Creation Phase.
- In this phase we know js engine creates global object ‘this’ in memory, the outer environment is also created and in that creation phase as the parser runs through your code. It recognizes where you have created the variables and where you have created functions. So it set up memory space for variables and functions and it’s that step that is somewhat confusingly called Hoisting. It’s not moving code to the top of the page.
- Before your code is executed line by line the js engine set aside a memory space for the variables in the entire code and all of the functions you have created. So those variables and functions exist in memory. So when the code begins to execute line by line it can access them, however, when it comes to variables it’s different.
- The function is entirely placed into the memory space but the assignments of variables are set in the next phase
Execution Phase
. So when js engine setups memory space for“a”
it doesn’t know it’s value unit it starting executing this code. It puts a placeholder“undefined”
. All variables in js are initially set toundefined
and functions are set in memory in their entirety. - That’s why it’s a bad idea to rely on hoisting in any way.
Example 1
var a ;
console.log(a); //undefined
Example 2
console.log(a); //Error : a is not defined
undefined
and not defined
are not the same thing in js. In js undefined
is not just a word, It’s a special value (undefined is a special keyword) that javascript has in it internally i.e the variable hasn’t been set.
Example 3 To prove above statement.
var a ;
console.log(a); //undefined
if(a === undefined){
console.log(“a is undefined”); // this will work
}else{
console.log(“a is defined”);
}
Example 4 Output :Uncaught reference error : a is not defined.
console.log(a);
if(a === undefined){
console.log(“a is undefined”);
}else{
console.log(“a is defined”);
}
- It didn’t find var a so it didn’t set up memory space
- Never do var a = undefined;
- Never set a variable equal to undefined. It’s perfect js but it’s dangerous undefined means a programmer never set that value. It helps in debugging code. It would be difficult to identify that if you set it or js engine set it if a certain value is undefined
Example 1
function b(){
console.log(“Called b!”);
}
b();
console.log(a);
var a = “Hello World”;
console.log(a);
Output
Called b!
undefined
Hello World
#BIGWORD Single-Threaded - One command at a time (under the hood of browser maybe not) #BIGWORD Synchronous - One at a time and in order.
#BIGWORD Invocation - Calling a function, in js by using parentheses ()
What happens when you invoke a function in js?
Example 1
function b(){
}
function a(){
b();
}
a();
- First of all global execution context is created and code is executed.
a()
- New execution context is created and executed and placed on the execution stack.- Whenever you execute a function in js. A new execution context is created and pushed on the execution stack. It will have its own space for variables and functions and then it will execute line by line. However, if I have another function call inside the function it will stop that execution and create another execution context and run that code. This is how to function execution happens in javascript.
- Once b() is executed it will be popped out of the stack then a() back down to global. The order lexically doesn’t matter nor does the rest of the code that happens to be surrounding those function calls. Explained in example 2
Example 2
function a(){
b();
var c;
}
function b(){
var d;
}
a();
var d;
This doesn’t matter both functions are in memory during the create phase of the initial execution of the global context
Execution process of example 2 First of all a() at the bottom will be invoked and it’s pushed on the execution stack then that becomes the currently running code. var d will not be executed yet because js is synchronous, one line at a time. Then a() will create its space and execute b(), now this will create its new execution context and pushed on the top of stack and it will run it’s single line of code only once it’s finished we will go back to finishing a() when the function finishes the execution context is popped off the stack. Now current execution context is again a() it will run another line of code which hasn’t be executed yet in this execution context i.e var c and when a() is finished it’s popped off the stack and the next line of code that hasn’t been executed yet in the global execution context is run i.e var d.
#BIGWORD Variable environment - Where the variables live and how they relate to each other in memory.
Example 1
function b(){
var myVar;
}
function a(){
var myVar = 2;
b();
}
var myVar = 1;
a();
Explanation
- At first global execution, context is created and
myVar = 1
is pushed in memory space - Then it hits invocation of
a()
, A new execution context is created for a() myVar = 2 into that execution context. Every execution context has it’s own variable environment - Then it invokes
b()
and new execution context is created forb()
myVar = undefined
- This has to do something with a scope just means where we can see variable each variable is defined in its execution context because it’s within a function all three myVar is distinct
Example 1
function b(){
console.log(myVar);
}
function a(){
var myVar = 2;
b();
}
var myVar = 1;
a();
Output
1
Explanation
- First of all global execution context is pushed on the stack with
myVar = 1
- Then
a()
gets executed and its execution context is created and executedmyVar = 2
and it’s pushed on the stack. - Then
b()
gets executed with its execution context. There is no myVar in its execution context environment. Each execution context has its variable object“this”
- Every execution context has reference to its outer environment. In the case of function
b()
, it’s the outer environment is the global execution context and that’s also the case in functiona()
even thougha()
is exactly belowb()
in execution stack as far as what code is going to run. - Lexical environment - Where something is written physically in your code is important.
b()
lexically sits on top of the global environment. If js can’t find the variable in the current execution context it looks at the outer reference and go looks for variable there somewhere down below it in the execution stack and the outer environment where it points is going to depend on where the function sits lexically. So it’s the outer environment is the global execution context.- This chain of references to the outer environment is called Scope Chain. Scope means where I can access the variable and chain is links of outer env.
- We can change this by changing the lexical environment of the function.
b()
is lexically in the global environment.
Example 2
function a(){
var myVar = 2;
function b(){
console.log(myVar);
}
b();
}
var myVar = 1;
a();
Output
2
Explanation
Here we have changed the lexical environment of b()
now the outer reference of b()
would be execution context of a()
because b()
is physically sitting inside the function a()
Example 3
function a(){
function b(){
console.log(myVar);
}
b();
}
var myVar = 1;
a();
Output
1
Explanation
Now lexical outer environment of function b()
is a()
and as myVar is not defined in a()
it will check the declaration of myVar in its global outer environment.
#BIGWORD Scope - It’s where a variable is available in your code. It could be a new variable or a new copy.
- ES6 - Providing a new way of declaring the variable
“let”
- let allows block scoping
Example 1
if(a>b){
let c = true;
}
#BIGWORD Asynchronous - More than one at a time
- Rendering engine <-> The javascript engine <-> HTTP request
- It happens asynchronously inside the browser but synchronously inside the javascript engine.
- How does this happen inside the js engine?
- There is an execution stack and event queue like click event and the HTTP request is placed in the queue. The event queue is looked at by javascript when the execution stack is empty
- Once the execution stack is empty then js periodically looks at the event queue and waits for something to be there and check if this function to execute once the event was triggered
- So it sees click event it processes
clickHandler()
and creates the execution context for that function once that function is processed next item in the queue moves up. It will not get processed until the execution stack is empty. - It’s not asynchronous actually, the browser is putting things in queue asynchronously but the code is running line by line and when execution context is empty it processes the event in the queue.
Example 1 - How callbacks work
function waitThreeSeconds(){
var ms = 3600 + new Date().getTime();
while(new Date() < ms) {}
console.log(“Finished function”);
}
function clickHandler(){
console.log(“Click event”);
}
document.addEventListener(“click”,clickHandler);
waitThreeSeconds();
console.log(“Finished execution”);
If you want a gist of the actual document, subscribe to the newsletter.