---
title: "Reading the ECMA-262: How Declarations at Global Level Work"
description: "To understand hoisting and variable scoping better, let's dive into the ECMAScript specification of global declarations."
lang: "en"
tags: ["JavaScript", "ECMA-262"]
pubDate: 2024-06-22T00:00:00.000Z
---

There are four kinds of context in which variable or function declarations would occur: Global, module, function, and block. This article focuses on the **global** context.

## Steps in Specification of Declarations in Global Context

A JavaScript engine instance is responsible for the code execution. The engine will parse the code to identify what kinds of statements and expressions there are.

But before actually executing the code line by line, the engine needs to set up the environment that is essential for executing.

By design, all JavaScript code should run in its corresponding execution context in a single execution stack. So, the engine needs to create the first execution context and push it to the stack.

Here are the steps in the specification of how a piece of global code is processed before execution:

1. The engine **creates and initializes a `Realm` for the execution context**: ([InitializeHostDefinedRealm](https://262.ecma-international.org/13.0/index.html#sec-initializehostdefinedrealm))
   1. Create `[[Intrinsics]]` = new Record
      1. Set properties of `realmRec.[[Intrinsics]]` for engine internal use. `(%Object%, %Function%, %Array%, %String%, %Number%, %Map%, %Set%, %Date%…)`
   2. Create `[[GlobalObject]]` = `undefined`
   3. Create `[[GlobalEnv]]` = `undefiend`
      1. Create an empty `global` object and set it to `realmRec.[[GlobalObject]]`
      2. `globalEnv` ← a new Lexical Environment with:
         1. outer environment ← `null`
         2. EnvironmentRecord ← Create a global environment record with:
            1. `[[ObjectRecord]]` ← Create a object Environment Record with `global` as its binging object
            2. `[[GlobalThisValue]]` ← the `global` object
            3. `[[DeclarativeRecord]]` ← Create a declarative Environment Record without bindings
            4. `[[VarNames]]` ← Create a new empty List
   4. Set all properties (global object, functions…) to `realmRec.[[GlobalObject]]`
2. The engine **sets the first execution context** ([ScriptEvaluation](https://262.ecma-international.org/13.0/index.html#sec-runtime-semantics-scriptevaluation))
   1. `scriptContext` ← a new ECMAScript code execution context with:
      1. `Function` ← `null`
      2. `Realm` ← `scriptRecord.[[Realm]]`
      3. `ScriptOrModule` ← `scriptRecord`
      4. `VariableEnvironment` ← `scriptRecord.[[Realm]].[[GlobalEnv]]`
      5. `LexicalEnvironment` ← `scriptRecord.[[Realm]].[[GlobalEnv]]`
3. The engine **instantiates the global declarations** ([GlobalDeclarationInstantiation](https://262.ecma-international.org/13.0/index.html#sec-globaldeclarationinstantiation))
   1. `envRec` = environment record of `scriptRecord.[[Realm]].[[GlobalEnv]]`
   2. Get `LexicallyDeclaredNames` and `VarDeclaredNames` (function + var) from script
   3. Conflict Checks
      1. for Lexical Declarations
      2. for Variable Declarations (only conflict with lexical not allowed)
   4. Split `VarScopedDeclarations`
      1. Pick Function Declarations: If there’re duplicated functions with same name, only take the last
      2. Pick Variable Declarations: If there’re duplicated variables with same name, only take the first
   5. Instantiate Lexical Declarations
      1. const → `envRec.CreateImmutableBinding(name)`, let → `envRec.CreateMutableBinding(name)`
         - Note: Lexically declared names are only instantiated here but not initialized
         - `[[DeclarativeRecord]].CreateMutableBinding(name)` and `[[DeclarativeRecord]].CreateImmutableBinding(name)`
   6. Instantiate and initialize Function Declarations
      - `envRec.CreateGlobalFunctionBinding(name, InstantiateFunctionObject, false)`
        - Create and initialize a global function binding in the `[[ObjectRecord]]` component of a global Environment Record.
   7. Instantiate and initialize Var Declarations with `undefined`
      - `envRec.CreateGlobalVarBinding(name, false)`
        - Used to create and initialize to `undefined` a global var binding in the `[[ObjectRecord]]` component of a global Environment Record.
4. The engine **executes the code**
   1. Evaluate the assignments of values to `var`, `let`, and `const` variables when encountering these statements.

We can see the behavior known as “hoisting” in these steps:

1. Lexical declarations are only instantiated here but not initialized.
2. Function declarations are instantiated and initialized with the function object as its value
3. Var declarations are instantiated and initialized with `undefined` as its value

## Recap

Here is the outline of the steps to prepare a new execution context for a global code execution:

1. Create and initialize a `Realm` record with its `[[Intrinsics]]`, `[[GlobalObject]]`, and `[[GlobalEnv]]`. The environment record of `[[GlobalEnv]]` has some important internal slots:
   1. `[[ObjectRecord]]`
   2. `[[DeclarativeRecord]]`
   3. `[[GlobalThisValue]]` ← point to the `[[GlobalObject]]` object
2. Create first ECMAScript code execution context with `Realm`, and its `[[GlobalEnv]]` for `VariableEnvironment` and `LexicalEnvironment`
3. Instantiate the declarations in the `scriptRecord` to the environment record of `scriptRecord.[[Realm]].[[GlobalEnv]]`
   1. lexical → bond to `[[DeclarativeRecord]]`, not initialized
   2. var → bond to `[[ObjectRecord]]`, initialized with `undefined` as its value
   3. function → bond to `[[ObjectRecord]]`, initialized with the function object as its value
4. Finally the engine can start executing the code and evaluating the assignments.
