What is scope
A scope is the accessibility of variables, functions, and objects in specific parts of the code run time. In other words, a scope determines the visibility of variables and other resources in a code block
There are two working models for scopes
- Lexical scope (static scope)
- Dynamic scope
Lexical scope
Lexical scope, also known as static scope, is the scope defined at the lexical stage. In other words, the lexical scope is determined by where you write the variable and block scope when you write the code. The JS scope uses lexical scope
Here’s an example:
var a = 2
function foo() {
var b = 2
console.log(a + b)
}
foo() / / 4
Copy the code
Function foo defines what variables it can get, so if foo has a in it, it takes it directly, otherwise it goes up one level.
Example 2:
var a = 2
function bar() {
console.log(a)
}
function foo() {
var a = 3
bar()
}
foo() / / 2
Copy the code
Bar will only look up from its defined position, that is, find a to be 2
Dynamic scope
The scope of a function is determined at the time the function is called, and bash is dynamically scoped
Save the following code as shell to execute the final output is: 3
#! /bin/bash
a=2
foo() {echo $a
}
bar(){
a=3
foo
}
bar
Copy the code
Scope in Javascript
There are two types of scope in JavaScript
- Global scope
- Local scope
Global scope
The entire JavaScript document is a global function, and variables are defined outside of functions, so variables are globally scoped
var a = 1
Copy the code
You can access and change in any other scope
var a = 1
console.log(a) / / 1
function bar() {
console.log(a)
}
bar() / / 1
Copy the code
Local scope/function scope
Variables defined within a function are in the local scope. Variables are bound to functions. Each function has a different scope and is not accessible from other functions
// Global scope
function foo() {
// local scope
var a = 1
console.log(a) / / 1
}
// Global scope
function bar () {
// local scope
console.log(a) // Uncaught ReferenceError: a is not defined
}
Copy the code
Scope subdivision
Nested scopes
Scope nesting occurs when a block or function is nested within another or function, so that a variable cannot be found in the current scope and the engine will continue searching in the outer nested scope until it finds that variable or reaches the outermost scope
function foo(a) {
console.log(a + b)
}
var b = 2
foo(2) / / 4
Copy the code
In foo, if b is undefined, it looks up one level in scope and stops looking.
Scoped look-ups stop when the first matching identifier is found. Multiple layers of nested scopes can define identifiers of the same name. This is called the “masking effect” (internal identifiers “mask” external identifiers)
Ex. :
var a = 2
function foo() {
var a = 3
function bar () {
console.log(a)
}
return bar;
}
foo()() / / 3
Copy the code
Block scope
Unlike functions, statements like if, switch, while, and for do not create new scopes, but block scopes. If you use the VAR definition, you end up in an external scope
if (true) {var a = 1
}
if (false) {
var b = 2
}
console.log(a) / / 1
console.log(b) // Undefined is in the block scope. When using var declarations, where does it end up in the outer scope
for (var i = 0; i <10; i++){ }console.log(i) / / 10
Copy the code
Use try catch, with statements to create block scopes
try {
undefined(a)// Throw an error
} catch (err) {
console.log(err) // Normal execution
}
console.log(err) // Uncaught ReferenceError: err is not defined
Copy the code
The let and const keywords in ES6 support declaring local scopes within block statements
if (true) {var a = 1
let b = 2
const c = 3
}
console.log(a) / / 1
console.log(b) // Uncaught ReferenceError: b is not defined
console.log(c) // Uncaught ReferenceError: c is not defined
Copy the code
You can also create a display
if (true) {
var a = 1
{
let b = 2
const c = 3}}console.log(a) / / 1
console.log(b) // Uncaught ReferenceError: b is not defined
console.log(c) // Uncaught ReferenceError: c is not defined
Copy the code
Use block scope for garbage collection
function process(data) {}var someReallyBigData = { ... }
process(someReallyBigData)
var btn = document.getElementById("my_button")
btn.addEventListener("click".function click(evt) {
console.log("button clicked")})Copy the code
The click callback of the click function does not require the someReallyBigData variable. Be fooled by the process of theory After execution, data structures that take up a lot of space in memory can be reclaimed. However, because the click function forms a closure that covers the entire scope, the JavaScript engine is most likely still storing this structure
Block scope solves this problem
function process(data) {} {let someReallyBigData = { ... }
process(someReallyBigData)
}
var btn = document.getElementById("my_button")
btn.addEventListener("click".function click(evt) {
console.log("button clicked")})Copy the code
ascension
Declarations are moved from where they appear in the code to the top, a process called variable promotion
Promotion of variables
Look at the following code
a = 2
var a;
console.log(a) / / 2
Copy the code
console.log(a) // undefined
var a = 2
Copy the code
The reason for this is that the engine compiles the Javascript code before it interprets it, and part of the compilation phase is finding all the declarations and associating them with the appropriate scope
When the compiler sees var a = 2, it sees two declarations var a; And a = 2; The first definition declaration is made at compile time. The second assignment declaration is left in place for execution so the above code is processed as follows
var a;
a = 2;
console.log(a)
Copy the code
var a;
console.log(a)
a = 2 // Stay where you are
Copy the code
The whole process above is called promotion, and in general there is declaration before assignment
Note: Only the declaration itself is promoted; assignment or other running logic is left in place
Enhancement of function
Look at the following code
foo()
function foo() {
console.log(a) // undefined
var a = 2;
}
Copy the code
The declaration of the foo function is enhanced because the first line can be called and executed normally, and the above code can be interpreted as follows
function foo() {
var a;
console.log(a)
a = 2
}
foo()
Copy the code
Note that function expressions are not promoted
foo() // Uncaught TypeError: foo is not a function
var foo = function bar() {}Copy the code
The above code can be interpreted in the following form
var foo;
foo()
foo = function() {
varbar = ... self... }Copy the code
Function is preferred
Both function declarations and variable declarations are enhanced. Functions are promoted first, then variables.
Ex. :
foo() / / 1
var foo; // Declare variables
function foo() {
console.log(1)}// Declare the function
foo = function() {
cosnole.log(2)}Copy the code
The result will print 1. If the variable is promoted first, TypeError will appear.
function foo() {
console.log(1)
}
foo() / / 1
foo = function() {
console.log(2)}Copy the code
Var foo though appears in function foo()… Before the declaration, but it is a duplicate declaration and is directly ignored. Function declarations are promoted before ordinary variables.
Note: The following function declaration can override the previous example:
foo(); / / 3
function foo() {
console.log(1)}var foo = function() {
console.log(2)}function foo() {
console.log(3)}Copy the code
Try to avoid writing this code
Execution environment (Execution context)
The execution environment (execution context) defines other data that variables or functions have access to and determines their respective behavior. Each execution environment has a variable object associated with it, and all variables and functions defined in the environment are stored in this object
Global execution environment
The global execution environment is the Window object in a WEB browser, so all global variables and functions are created as properties and methods of the window. After all code in an execution environment is executed, the environment is destroyed, along with all variables and function definitions saved in it. (The global environment is not destroyed until the application exits – the web page or browser is closed
Function execution environment
Every function has an execution environment, and when the execution stream enters a function, the environment of the function is pushed into an environment stack. After the function executes, the stack ejects its environment, and control returns to the previous execution environment, with the browser always executing the execution environment at the top of the stack
The execution environment has two phases
1. Creation phase
When a function is called but its code has not yet been executed
- Create a variable (activity) object
- Create scope chains
- Set the context, that is
this
The variable object
Also known as an active object, it contains all variables, functions, and other declarations defined in the execution environment. When a function is called, the interpreter scans all of its resources including function arguments, variables, and other declarations. The initial value of the variable object contains the arguments object
'variableObject': {}Copy the code
The scope chain
The scope chain is created after the variable object. The scope chain itself contains variable objects. A scope chain is an ordered access to all variables and functions that the execution environment has access to
'scopeChain': {}Copy the code
Abstract the execution environment into an object:
executionContextObject = {
'variableObject': {},
'scopeChain': {},
'this': {}}Copy the code
Ex. :
function foo () {
var a = 1;
function bar () {
var b = 1;
}
bar()
}
Copy the code
Foo ()’s active object at creation time is: arguments,a,bar Foo () ‘s scope chain is: Foo > window foo() this is the execution environment for window foo() [Img-AHY5xUNQ-1639723468249] (EvernotecID :// 328b33FE-ED00-4b09-8BC9-557510243583 /appyin xiangcom/33490301/ENResource/p120)]
2. Implementation phase
In the execution phase, the values in the variable object are assigned and the code is finally executed
Scope chains and free variables
scope
The nested relationships of scopes form a scope chain, which is created for variable objects when code is executed in the execution environment.
Ex. :
function foo () {
var a = 1
function bar() {
var a = 2}}Copy the code
In this example, the scope chain of the bar function is bar>foo>window(global) and the scope chain of the foo function is foo>window(global)
The scope chain is mainly used to query identifiers (variables and functions). Identifier (variables and functions) parsing is the process of searching identifiers level by level along the scope chain, while the scope chain is to ensure orderly access to variables and functions
Free variables
What is a free variable
A variable that exists in, but is not declared in, the current scope
Ex. :
var b = 2;
function foo() {
var a = 1
function bar() {
var c = b + a
}
}
Copy the code
In the above example, B and A are not declared in scope bar, so A and B are free variables. Once a free variable appears, there will definitely be scope chain, and then the corresponding variable can be found according to the scope chain search mechanism.
conclusion
Scopes and scope chains are a very important part of the foundation of Javacript, and understanding them will help you learn about closures.
Reference documentation
Understanding Scope in JavaScrip
Chiba’s blog