The relationship between the function scope, the calling object, and the closure of Javascript is subtle, and there are a lot of articles about them, but I don't know why many novices are hard to understand. I will try to express my own understanding in the more popular language.
Scope scope
A function in Javascript is a lexical scope, which means that the function runs in its scope when it is defined rather than within the scope at which it is executed. This is what the Rhino book says. But when "defined" and "executed (called)" These two things are not clear to some people. Simply put, a function A at "definition" is the function A () {} When the statement executes is defined by the time, and A is called a () when the statement executes. These two concepts must be clearly divided.
What is the lexical scope (hereinafter referred to as "scope", unless specifically specified)? It is an abstract concept, it is a "scope", scope in English is the meaning of the scope. The scope of a function is the "scope" in which it is defined, that is, the "scope" of its outer layer, which contains the variable attributes of the outer layer, which is set to an internal state of the function. When a global function is defined, the "scope" of the global (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. Yun Ding Casino
According to the above, a function scope 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, and the lexical scope is also known as the static scope.
Calling Object Call objects
The calling object of a function is dynamic, and it 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 invokes 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 arguments object of the function, and the arguments object is the actual argument of the function. All local variables declared with the VAR statement are also defined in the calling object. At this point, the calling object is at the head of the scope chain, with local variables, function-form arguments, and Arguments objects all within the scope of the function. This time, of course, local variables, function-form arguments, and Arguments objects overwrite properties with the same name in the scope chain.
Relationships between scopes, scope chains, and call objects
My understanding is that the scope is abstract and the calling object is instantiated.
When a function is defined, it is actually the outer function execution, it determines the scope chain is actually its outer function call object chain, when the function is called, its scope chain is based on the definition of the scope chain (its outer function call object chain) plus an instantiated call object. So the function's scope chain is actually called the object chain. When a function is called, its scope chain (or chain of call objects) is actually a superset of the scope chain that it determines at the time it is defined.
The relationship between them can be expressed as: scope? Scope chain? Call object.
Too much of a mouth, for example:
View Source print?
2 |
var g = function () { return x; } |
Suppose we look at the global as a large anonymous function like this:
View Source print?
Then the example can be seen as:
View Source print?
3 |
var g = function () { return x; } |
- When a 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.
- The function f is defined when the scope chain of the function f is the scope chain of its outer layer, which is the ' Global Call object '.
- The function f (1) is executed, its scope chain is the new F (1) Call object plus the function f is defined when the scope chain, that is, ' F (1) Call Object--Global Call object '.
- The function g (which is to be returned to G1, named G1 Bar) is defined in F (1) and its scope chain is the scope chain of its outer function f (1), that is, ' F (1) Call Object--Global Call object '.
- function f (1) Returns the definition of function g to G1.
- The function G1 is executed, and its scope chain is the new G (1) Call object plus the outer f (1) Scope chain, the ' G1 call Object->f (1) Call Object--Global Call object '.
That's a pretty clear look.
Closed Bag Closuer
A simple argument for closures is that when nested functions are called outside of nested functions, closures are formed.
The previous example is actually a closed packet. G1 is defined inside F (1) and is executed after F (1) is returned. As you can see, one effect of closures is that when the nested function f is returned, its internal resources are not freed. When the G function is called externally, G can access the internal variables of F. Based on this feature, you can write a lot of elegant code.
For example, to make a unified counter on a page, if the closure of the wording, you can write:
View Source print?
01 |
var counter = ( function () { |
03 |
var fns = { "get" : function () { return i;}, |
04 |
"inc" : function () { return ++i;}}; |
11 |
var c_value = counter.get(); //now c_value is 2 |
In this way, a variable i is maintained in memory, and the value of I is not directly manipulated anywhere else in the program, only through the two operations of the counter.
At SetTimeout (FN, delay), we cannot pass arguments to the function handle of FN, but we can bind the required parameters to the FN by means of a closure method.
View Source print?
1 |
for ( var i=0,delay=1000; i< 5; i++, delay +=1000) { |
2 |
setTimeout( function () { |
3 |
console.log( ‘i:‘ + i + " delay:" + delay); |
In this way, the printed values are
View Source print?
Instead of using closures, you can easily bind the parameters you want to pass in:
View Source print?
1 |
for ( var i=0, delay=1000; i < 5; i++, delay += 1000) { |
3 |
setTimeout( function () { |
4 |
console.log( ‘i:‘ +a+ " delay:" +_delay); |
Output:
View Source print?
The closure also has a very common place, that is, when binding the callback function of the event. It is also true that a bound function handle cannot be used as a parameter, but it can be bound in the form of a closed packet.
JavaScript lexical scopes and calling objects