Scopes are one of the most important concepts of JavaScript, and to learn JavaScript you need to understand how JavaScript scopes and scope chains work. Today's article provides a simple introduction to JavaScript scopes and scope chains, hoping to help you learn JavaScript better.
JavaScript scopes
Any programming language has the concept of scope, simply speaking, scope is the scope of the variable and function, that is, the scope of the variable and function visibility and life cycle. In JavaScript, the scope of a variable has both global scope and local scope.
1 scope (global scope)
Objects that can be accessed anywhere in the code have global scope, typically with global scope in the following situations:
(1) The outermost function and the variables defined outside the outermost function have global scope, for example:
123456789101112 |
var
authorName=
"山边小溪"
;
function
doSomething(){
var
blogName=
"梦想天空"
;
function
innerSay(){
alert(blogName);
}
innerSay();
}
alert(authorName);
//山边小溪
alert(blogName);
//脚本错误
doSomething();
//梦想天空
innerSay()
//脚本错误
|
(2) All variables that are directly assigned to the last definition are automatically declared to have global scope, for example:
12345678 |
function
doSomething(){
var
authorName=
"山边小溪"
;
blogName=
"梦想天空"
;
alert(authorName);
}
doSomething();
//山边小溪
alert(blogName);
//梦想天空
alert(authorName);
//脚本错误
|
The variable blogname has a global scope, and AuthorName cannot be accessed outside the function.
(3) All Window object properties have global scope
In general, the built-in properties of the Window object have global scope, such as Window.name, Window.location, Window.top, and so on.
2 scope (local scope)
In contrast to the global scope, local scopes are generally accessible only within a fixed code fragment, the most common of which is inside the function, and in some places it is also seen that this scope is called a function scope, such as the Blogname in the following code and the function Innersay only have local scope.
123456789 |
function
doSomething(){
var
blogName=
"梦想天空"
;
function
innerSay(){
alert(blogName);
}
innerSay();
}
alert(blogName);
//脚本错误
innerSay();
//脚本错误
|
Scope chain (Scope Chain)
In JavaScript, functions are objects, and in fact, everything in JavaScript is an object. function objects, like other objects, have properties that can be accessed through code and a series of internal properties that are accessible only by the JavaScript engine. One of the internal properties is [[Scope]], defined by the ECMA-262 Standard third edition, which contains a collection of objects in the scope of the function being created, called the scope chain of the function, which determines which data can be accessed by the function.
When a function is created, its scope chain is populated with data objects that can be accessed by creating the scope of this function. For example, define a function such as the following:
1234 |
function add(num1,num2) { var sum = num1 + num2; return sum; } |
When the function add is created, it fills a global object in its scope chain, which contains all the global variables, as shown (note: The picture shows only a subset of all variables):
The scope of the function add will be used at execution time. For example, execute the following code:
Executing this function creates an internal object called the runtime context (execution context), which defines the environment at which the function executes. Each run-time context has its own scope chain, which is used for identifier resolution, when the runtime context is created, and its scope chain is initialized to the object contained by [[Scope]] of the currently running function.
These values are copied into the scope chain of the run-time context, in the order in which they appear in the function. Together they form a new object called the "Activation Object", which contains all the local variables, named arguments, parameter sets, and this of the function, which is then pushed into the front of the scope chain, and the active object is destroyed when the run-time context is destroyed. The new scope chain is as follows:
During the execution of a function, no variable is encountered, and an identifier parsing process is passed to determine where to get and store the data. The process from the scope chain head, that is, starting from the active object search, find an identifier of the same name, if found to use this identifier corresponding to the variable, if not found to continue to search the scope chain of the next object, if the search all objects are not found, the identifier is considered undefined. Each identifier undergoes such a search process during the execution of the function.
Scope Chain and code optimization
As you can see from the structure of the scope chain, the deeper the identifier is in the scope chain of the run-time context, the slower the read and write speed will be. As shown, because global variables always exist at the end of the run-time context chain, finding global variables is the slowest when identifiers are resolved. Therefore, when writing code, you should use as few global variables as possible, using local variables as much as you can. A good rule of thumb is that if a cross-scope object is referenced more than once, it is stored in a local variable before it is used. For example, the following code:
12345 |
function changecolor () { document.getelementbyid ( function () { document.getelementbyid ( "Targetcanvas" "red" Code class= "JavaScript plain";      } |
This function refers to the two global variable document and finds that the variable must traverse the entire scope chain until it is finally found in the global object. This code can be rewritten as follows:
123456 |
function
changeColor(){
var
doc=document;
doc.getElementById(
"btnChange"
).onclick=
function
(){
doc.getElementById(
"targetCanvas"
).style.backgroundColor=
"red"
;
};
}
|
This code is simple and will not show a huge performance boost after rewriting, but if there are a large number of global variables in the program that are accessed from time to time, the rewritten code performance can be significantly improved.
Change the scope chain
The runtime context is unique for each execution of the function, so calling the same function multiple times will result in multiple runtime contexts being created and the execution context destroyed when the function finishes executing. Each run-time context is associated with a scope chain. In general, the scope chain is only affected by the WITH statement and catch statement during the run-time context.
The WITH statement is a quick way to apply an object to avoid writing duplicate code. For example:
1234567891011121314 |
function initUI(){
with
(document){
var
bd=body,
links=getElementsByTagName(
"a"
),
i=0,
len=links.length;
while
(i < len){
update(links[i++]);
}
getElementById(
"btnInit"
).onclick=
function
(){
doSomething();
};
}
}
|
Using the width statement here to avoid writing the document multiple times seems more efficient and actually creates performance problems.
When the code runs to the WITH statement, the scope chain of the run-time context is temporarily changed. A new Mutable object is created that contains all the properties of the object specified by the parameter. This object will be pushed into the head of the scope chain, which means that all local variables of the function are now in the second scope chain object, so the access cost is higher. As shown in the following:
Therefore, you should avoid using the WITH statement in your program, in which case you can improve performance by simply storing the document in a local variable.
The other one that changes the scope chain is the catch statement in the Try-catch statement. When an error occurs in a try code block, the execution jumps to the catch statement, and then pushes the exception object into a Mutable object and puts it in the scope's head. Inside a catch code block, all local variables of the function are placed in the second scope chain object. Example code:
12345 |
try { doSomething(); } catch (ex){ alert(ex.message); //作用域链在此处改变 } |
Note that once the Catch statement finishes executing, the scope chain opportunity returns to the previous state. Try-catch statements are useful in code debugging and exception handling, so it is not recommended to avoid them altogether. You can reduce the performance impact of catch statements by optimizing your code. A good pattern is to delegate the error to a function handler, for example:
12345 |
try { doSomething(); } catch (ex){ handleError(ex); //委托给处理器方法 } |
After the optimized code, the HandleError method is the only code executed in the Catch clause. The function receives the exception object as a parameter, so you can handle the error more flexibly and uniformly. Because only one statement is executed and there is no access to local variables, temporary changes to the scope chain do not affect code performance.
JavaScript Development Advanced: Understanding JavaScript scopes and scope chains