They are different concepts but related: we need to define a related concept – Execution Context & it’s stack to understand.
Lexical Environment is the internal JS engine construct that holds identifier-variable mapping (here identifier refers to the name of variables/functions, and variable is the reference to actual object (including the function type object) or primitive value). A lexical environment also holds a reference to a parent lexical environment.
Now, for every execution context:
- a corresponding lexical environment is created and
- if any function is created in that execution context, reference to that lexical environment is stored at the internal property ([[Environment]]) of that function. So, every function tracks the lexical environment related to the execution context it was created in.
Every lexical environment tracks its parent lexical environment (that of parent execution context). As a result, every function has a chain of lexical environments attached to it.
Note: in JS a function is an object. Creating a function with a statement means creating an object of type Function. So, like other objects, a function can hold properties both internal and user defined.
Scope is a language agnostic concept that refers to the visibility of variables or functions to the executing code. In JS, a variable or function is visible to the executing code if it is there in the current lexical environment or in the lexical-environment-chain of the enclosing function. In case of global code, the chain does not exist.
Hope, you understand now…
Note: similar to the function, via the introduction of let and const in es6, when a block begins to execute (if block, for loop block etc), a new lexical environment is also created with the parent function’s lexical environment as parent.