Home  >  Article  >  Web Front-end  >  In-depth understanding of JavaScript lexical scope and calling objects_javascript skills

In-depth understanding of JavaScript lexical scope and calling objects_javascript skills

WBOY
WBOYOriginal
2016-05-16 17:47:34955browse

The relationship between function scope, calling objects and closures in Javascript is very subtle. There have been many articles about them, but I don’t know why many novices have difficulty understanding them. I will try to express my own understanding in more popular language.
Scope Scope
Functions in Javascript belong to lexical scope, which means that the function runs in the scope when it is defined instead of when it is executed. This is what the rhino book says. But some people are confused about the two things "when defined" and "when executed (called)". To put it simply, when a function A is "defined", it is function A(){}. When the statement is executed, it is when the function is defined, and when A is called, it is when the statement A() is executed. These two concepts must be clearly distinguished.
What exactly is lexical scope (hereinafter referred to as "scope" unless otherwise specified)? It is an abstract concept. To put it bluntly, it is a "scope", and scope means scope in English. The scope of a function is the "scope" it is in when it is defined, that is, its outer "scope". This "scope" includes the outer variable attributes. This "scope" is set to the function's an internal state. When a global function is defined, the "scope" of the global function (the outer layer of the function) is set to an internal state of the global function. When a nested function is defined, the "scope" of the nested function (the outer function) is set to an internal state of the nested function. This "internal state" can actually be understood as a scope chain, see below.
According to the above statement, the scope of a function is the "scope" in which it is defined. Then the function scope in Javascript is determined when the function is defined, so it is a static scope. , lexical scope is also called static scope.
Call Object
The call object of a function is dynamic and is instantiated when the function is called. We already know that when a function is defined, its scope chain is determined. When the Javascript interpreter calls a function, it adds a new object (the calling object) to the front of the scope chain. A property of the calling object is initialized to a property called arguments, which references the function's Arguments object, which is the actual parameters of the function. All local variables declared with the var statement are also defined in this calling object. At this time, the calling object is at the head of the scope chain, and local variables, function formal parameters, and Arguments objects are all within the scope of this function. Of course, at this time, local variables, function formal parameters, and Arguments objects overwrite the properties with the same name in the scope chain.
The relationship between scope, scope chain and calling object
My understanding is that scope is abstract, while calling object is instantiated.
When a function is defined, which is actually when its outer function is executed, the scope chain it determines is actually the calling object chain of its outer function; when the function is called, its scope chain It is based on the scope chain determined at the time of definition (the calling object chain of its outer function) plus an instantiated calling object. So the function's scope chain is actually the calling object chain. When a function is called, its scope chain (or calling object chain) is actually a superset of the scope chain determined when it was defined.
The relationship between them can be expressed as: scope? scope chain? calling object.
That’s too convoluted, let’s give an example:

Copy the code The code is as follows:

function f(x) {
var g = function () { return x; }
return g;
}
var g1 = f(1);
alert(g1()) ; //Output 1
Suppose we regard the global situation as a large anonymous function similar to the following:
(function() {
//This is the global scope
})();
Then the example can be seen as:
(function() {
function f(x) {
var g = function () { return x; }
return g;
}
var g1 = f(1);
alert(g1()); //Output 1
})();

When the global large anonymous function is defined, it has no outer layer, so its scope chain is empty.
The global large anonymous function is executed directly, and there is only one 'global call object' in the global scope chain.
Function f is defined. At this time, the scope chain of function f is its outer scope chain, that is, the 'global call object'.
Function f(1) is executed, and its scope chain is the new f(1) calling object plus the scope chain when function f was defined, that is, 'f(1) calling object->global call object'.
Function g (it will be returned to g1, let’s name it g1) is defined in f(1), and its scope chain is the scope chain of its outer function f(1), that is, ' f(1) calling object->global calling object'.
Function f(1) returns the definition of function g to g1.
Function g1 is executed, and its scope chain is the new g(1) calling object plus the scope chain of the outer f(1), that is, 'g1 calling object->f(1) calling object- >Global call object'.
It will be very clear if you look at it this way.
Closuer
A simple way of saying closure is that when a nested function is called outside the nested function, a closure is formed.
The previous example is actually a closure. g1 is defined inside f(1), but is executed after f(1) returns. It can be seen that one effect of closure is that after the nested function f returns, its internal resources will not be released. When the g function is called externally, g can access f's internal variables. Based on this feature, a lot of elegant code can be written.
For example, if you want to make a unified counter on a page, if you use closure, you can write it like this:
Copy code The code is as follows:

var counter = (function() {
var i = 0;
var fns = {"get": function() {return i;},
"inc": function() {return i;}};
return fns;
})();
//do something
counter.inc();
//do something else
counter.inc();
var c_value = counter.get(); //now c_value is 2

In this way, one is maintained in the memory Variable i, the value of i cannot be directly manipulated elsewhere in the entire program, only through the two operations of counter.
During setTimeout(fn, delay), we cannot pass parameters to the function handle fn, but we can bind the required parameters to the inside of fn through the closure method.
Copy code The code is as follows:

for(var i=0,delay=1000; i< ; 5; i , delay =1000) {
setTimeout(function() {
console.log('i:' i " delay:" delay);
}, delay);
}

In this way, the printed values ​​are all
i:5 delay:6000
i:5 delay:6000
i:5 delay:6000
i:5 delay:6000
i:5 delay:6000
Using closure instead can easily bind the parameters to be passed in:
Copy code The code is as follows:

for(var i=0, delay=1000; i < 5; i , delay = 1000) {
(function(a , _delay) {
setTimeout(function() {
console.log('i:' a " delay:" _delay);
}, _delay);
})(i, delay) ;
}

Output:
i:0 delay:1000
i:1 delay:2000
i:2 delay:3000
i:3 delay :4000
i:4 delay:5000
Closures are also commonly used when binding event callback functions. For the same reason, bound function handles cannot be used as parameters, but parameters can be bound in the form of closures.
Summary
The lexical scope and scope chain of a function are different things. The lexical scope is an abstract concept, and the scope chain is a chain of instantiated calling objects.
When a function is defined, it is also when its outer function is executed.
The lexical scope of a function is determined when it is defined, but it is still an abstract concept and cannot and cannot be instantiated.
When a function is defined, it also determines one thing, which is the scope chain of its outer function, which is instantiated.
When a function is called multiple times, its scope chain is different.
Closures are powerful. The Rhinoceros book is right, if you understand these things, you can call yourself an advanced Javascript programmer. Because by making good use of these concepts, you can play with many design patterns of Javascript.
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn