What is Lexical Scoping?
In Javascript, each declared function creates its own scope. The scope of an inner function contains the scope of a parent function.
Lexical Scope Example
let val = 2
function multiply(x) {
let result = val * x
return result
}
console.log('answer:', multiply(6)) // answer: 12We have variables defined in the local execution context and variables in the global execution context. One complexity of JavaScript is how it looks for variables. If it can’t find a variable in its local execution context, it will look for it in its calling context. And if not found there in it calling context, it is looking in the global execution context. (And if it does not find it there, it’s undefined). The function has access to variables that are defined in its calling context. The formal name of this phenomenon is the lexical scope.
Here is another example:
var outerFunction = function(){
if(true){
var x = 5;
//console.log(y); //ReferenceError: y not defined
}
var nestedFunction = function() {
if(true){
var y = 7;
console.log(x); //x will still be known prints 5
}
if(true){
console.log(y); //prints 7
}
}
return nestedFunction;
}
var myFunction = outerFunction();
myFunction();In this example, the variable x is available everywhere inside of outerFunction(). Also, the variable y is available everywhere within the nestedFunction(), but neither are available outside of the function where they were defined.
The reason for this can be explained by lexical scoping. The scope of variables is defined by their position in source code. In order to resolve variables, JavaScript starts at the innermost scope and searches outwards until it finds the variable it was looking for. Lexical scoping is nice, because we can easily figure out what the value of a variable will be by looking at the code; whereas in dynamic scoping, the meaning of a variable can change at runtime, making it more difficult.
This ties in the topic of closure — a function which is able to remember and access its lexical scope even when that function is executing outside its lexical scope.
Lexical scope is the scope model used by the JavaScript language, which differs to some other languages which use dynamic scope. Lexical scope is the scope defined at lexing time.
Lexing time?
This dives into the mechanics of how the JavaScript engine works. Even though Javascript is known as an interpreted language, it compiles code immediately before executing it. For example the statement: var a = 3; is split into two separate steps at lexing time:
var aThis declares the variable in the scope, before code execution.a = 3This assigns the value 3 to the variable a, if it is found in the available scope.
The lexing phase of compilation determines where and how all identifiers are declared, and thus how they will be looked up during execution. This is the same mechanism which results in “hoisting” variables. The variables are not actually moved within the source code, the declarations simply occur during the lexing phase and so the JavaScript engine is aware of these before execution.