1
1
0
Cover image for JavaScript : Understanding The Weird Parts - Part 1: Glossary

JavaScript : Understanding The Weird Parts - Part 1: Glossary

Syntax Parser

A program that reads your code and determines what it does, and if the grammar is valid or not. Also known as compiler/interpreter.

A translation of your code is being given to the computer. The compiler engine does "extra stuff" behind the scenes.

Lexical Environment

Where something sits physically in the code you write. A lexical environment exists in programming languages in which where you write something is important. This determines how the computer will interact with the code.

In the above image, the code is written lexically inside the function.

Execution Context

A wrapper to help manage the code that is running. There are lots of lexical environments. Which one is currently running is managed via execution context. It can contain things beyond the written code. An execution context has two phases:

  1. Creation phase: In the creation phase, the global variables are set up, i.e. the window object and the this keyword that points to the window object. Also, JavaScript sets up memory space for the variable and function declarations, i.e the variables are initially set to undefined and the functions are stored entirely in memory (hoisting).

  2. Execution phase: In the execution phase, JavaScript executes the code line by line. It assigns the variables to their respective values and executes the functions if they are called/invoked.

Name/Value Pair

A name which maps to a unique value. The name may be defined more than once, but only one can have one value in any given context. That value may be more name value pairs. (Like an object can consist of more objects.)

Objects

A collection of name/value pairs.

"Address" and "Apartments" are objects.

The Global Execution Context

The Global Execution Context creates :

  1. A global object (window)

  2. this (special variable)

When you run a JS file even with no code, there are no errors. You can access the this keyword and the window object. These is because a global execution context was created. The JavaScript engine created it for us.

"Global" = "Not inside a function"

In JavaScript, when you create a variable which is not inside a function (global variable), it gets attached to the window object. Access them as :

window.a // Hello World*

In the below code, this is the order of things happening at a given time, i.e. this is the thread of execution:

  1. First, num is set to 3.

  2. Then, declaring the function multiplyBy2 and storing the function text (called the function definition) and the function name in memory. (When we hit (), we grab the this stored function text from memory and execute the function line by line.)*

  3. The string* 'Will'* is stored in the variable 'name'.

The body of the function was skipped because the function was never called. We never go inside a function if it isn't called.

The execution context does two things: Executing the code line at a time (execution phase), and creating global memory space (creation phase). The technical term for 'one line at a time' is single-threaded; we do the above 3 steps one step at a time. The technical term for 'order of execution' is synchronously. It means 'one after another' (top to bottom); we don't start from step 3, but do it it in order.

We call this execution context global, because we're not inside a function.

Local Execution Context

A local/function execution context is similar to the global execution context. It also has the above two phases:

  1. Creation phase: In the creation phase, the global variables are set up. In a function, instead of the window object, there's the arguments (an array-like) object that contains a list of all the arguments passed into the function on the time of its invocation. There's also the this keyword that points to the global window object. Here also, JavaScript sets up memory space for the variable and function declarations, i.e. the variables are initially set to undefined and the functions are stored entirely in memory (hoisting). However, anything passed as an argument will be set to that value in this phase.

  2. Execution phase: In the execution phase, JavaScript executes the code line by line. It assigns the variables to their respective values and executes the functions if they are called/invoked.

In the above code, first, num is set to 3, then function multiplyBy2 is declared. The variable output is set to undefined by default while it's waiting for the returned value of multiplyBy2(4) since JavaScript is single-threaded. multiplyBy2(4) is called. When a function is invoked (called via () ), it creates a new execution context (called the local execution context); this one has a local memory. Even here, the code will be run line by line. And we're paused before newOutput while we're busy executing multiplyBy2(4) since JavaScript is synchronous.

In the local memory, we assign the inputNumber parameter to 4 and variable result to 8 (just like we did in the global memory). This value will be returned and stored to output. On completion of the function, the local execution context is erased after the value is returned to output. This same process takes place for newOutput. The variable newOutput is set to undefined initially and finally set to 20.

Suppose, a function is running within a function, how do you know which function is currently running? Are you in global execution context, in the local or in a function within a function. A call stack is a special data structure which keeps track where the thread of execution is currently at, i.e what execution context we're currently in, i.e. what function is currently being run. At the bottom of the stack is the global execution context. Whichever function is running is on the top of the stack. On its completion, the local execution context gets erased and the function is popped off the stack (just like multiplyBy2(4) and multiplyBy29(10) ). How do you know the function is finished executing? The return statement or the curly brace! If there's no return, it returns undefined.

In the above code, first, the global execution context is created and placed in the call stack. Then, multiplyBy2 is called and placed on the top of the call stack and that function gets executed line by line. On completion, it's popped off from the stack and then multiplyBy2(10) is called and that is placed on the top of the call stack and starts getting executed line by line and finally popped off from the stack after completion.

The JavaScript engine starts executing the code line by line. First, it declares the function b and stores the function text and the function name in memory. Then, it declares function a and does the same with it. Finally, when it hits a(), a new execution context is created (its own this keyword is created) and placed on the call/execution stack.

When it hits b(), it creates a new execution context and is placed on the top of the stack.

When b finishes, it is popped of the stack. The variables in it are set up in the creation phrase.

The local/global memory contains essentially the variables and functions declared within the current context; the fancy term for this is variable environment.

It essentially means where the variables live and how they relate to each other in memory. Every function has its own execution context and every execution context has its own variable environment.

Hoisting

Function declarations are placed in their entirety (name and the code) in memory (as described above), so when they are called, they are referred to in the memory. For variables, it's a bit different. All variables in JavaScript are initially set to undefined. Hoisting puts a placeholder as undefined if the variable is defined later in the code. One should only use the code after it's defined. The placeholder means, "Oh I don't know what this value it is yet".

a; //undefined b; //undefined var a = b; b = 2; a; //undefined b; //2

Note 1: Hoisting takes place for variable and function declarations but nor function expressions. So, if the below code had function expressions, there would've been no hoisting and it would have not worked:

Note 2: let does hoist but doesn't get initialized.

foo() function foo() { return bar(); function bar() { // code } }

In the above code, a person with no hoisting knowledge would say that code will not be executed after return statement. But the function bar declaration bar is hoisted, so the code will work.

JavaScript and 'undefined'

As we saw in the above examples,undefined and not defined are not equal.

undefined is a value type, which JS sets to a variable if it is used in the code (and declared) but not set to a value. It's actually a value that takes up some memory space.

not defined means the engine does not have the variable a in memory. The below code outputs an error: a is not defined.

Never set a value to undefined. undefined tells the programmer that he forgot to set the value and so, it'll help in debugging.*

Discussion (4 comments)

avatar
avatar
Test
Apr 7, 2022
testing discussion
avatar
Hai
Jul 27, 2022
Jjjj
avatar
Hai
Jul 27, 2022
Jjjj
avatar
Hai
Jul 27, 2022
Kkk
avatar

Roksolana Zasiad

Twitter scholar. Lifelong food nerd. Beer fanatic. Pop culture geek. Subtly charming thinker. Love all things JavaScript and React 👨‍💻

Location

Internet

Work

Software Engineer at dynatrace