Nested functions (scope chain)
When nesting a function, you must note that the scope chain actually changes, which may not seem intuitive. You can put the following code into the firebug monitoring value changes.
VaR testvar = 'window attribute'; var O1 = {testvar: '1', fun: function () {alert ('o1: '+ this. testvar + '<') ;}}; var O2 = {testvar: '2', fun: function () {alert ('o2: '+ this. testvar) ;}}; o1.fun (); // output: O1: 1 <o2.fun (); // output: O2: 2o1. fun. call (O2); // output: O1: 2 <
This is the first example in this article.
VaR testvar = 'window attribute'; var O3 = {testvar: '3', testvar2: '3 ** ', fun: function () {alert ('o3: '+ this. testvar); // 'obj3' var inner = function () {alert ('o3-inner: '+ this. testvar); // 'window attribute 'alert ('o3-inner: '+ this. testvar2); // undefined (undefined)}; Inner () ;}}; o3.fun ();
Here we have changed other functions. This function is almost similar to the original function, but the difference is the writing of internal functions. It should be noted that the scope of the internal function Runtime is different from that of the external function. EXT allows you to specify the function scope when calling a function to avoid scope problems.
Variable Declaration
When initializing a variable, you must add the "Var" keyword. If not, this is a global variable. For example, in the following example, a variable is written inside the function. However, you only intend to declare a local variable, but it may also overwrite the value of the global variable. On the firebug "dom" tab, you can check "window" to view all global variables. If you find that there is a "K" or "x" variable, it proves that you have allocated this variable to an inappropriate scope. See the following example:
VaR I = 4; var J = 5; var K = 7; var fn = function () {var I = 6; k = 8; // note that there is no var before. Therefore, 8 is assigned to variable k! Alert (I); // 6 alert (j); // 5 alert (K + '-1'); // 8-1 x = 1; // This statement has two functions: create all variables X or overwrite all variables X}; FN (); alert (K + '-2 '); // 8-2 (note not 7-2)
It does not change much from the previous example. In addition, note that there is no var keyword before K in the function, so the local variable is not declared here, instead, it allocates a value to the global variable k. In addition, during the alert method execution, parameter I is a local variable that can be found currently, and its value is 6. However, if parameter J cannot be found in the current scopeScope chain)Search up until the J of the global variable is found.
Specify the scope in ext
As mentioned above, ext can flexibly handle the issue of scope when calling a function. Some of the content comes from DJ posts.
When calling a function, you canThisImagine a special (hidden) parameter in each function. At any time, JavaScript willThisPut it inside the function. It is based on a very simple idea: If a function is directly a member of an objectThisIs the object. If the function is not a member of an objectThisIs set to a global object (commonly, window objects in browsers ). The following internal functions clearly show this idea.
If a function is assigned to a variable, that is, it does not belong to a member of any objectThisThe parameter is changed to a Windows Object. The following is an example, which can be directly pasted to the firebug console:
VaR OBJ = {tostring: function () {return 'obj's range (in scope) ';}, // rewrite the tostring function to facilitate console execution. log (this) Output FUNC: function () {// The function here is directly subordinate to the object "object" console. log (this); var innerfunc = function () {// n the function here is not a direct member of a specific object, but a variable of another function. log (this) ;}; innerfunc () ;}}; obj. func (); // outputs "OBJ in the scope (in scope)" // outputs some related content of "window..."
By default, a parameter is called like this-but you can also manually change it.ThisParameters, but the syntax is slightly different. Change "obj. func ();" in the last row:
OBJ. func. Call (window); // output "window-related content..." // output "window-related content ..."
As shown in the preceding example,CallIt is actually another function (method ).CallIt is a built-in method of obj. func. (according to the characteristics of JavaScript, a function is an object .).
Change this wayThisScope. We can continue to use an example to modify the scope of innerfunc.ThisParameter, -- pointing to "Incorrect:
VaR OBJ = {tostring: function () {return 'obj's range (in scope) ';}, // rewrite the tostring function to facilitate console execution. log (this) Output FUNC: function () {// The function here is directly subordinate to the object "object" console. log (this); var innerfunc = function () {// n the function here is not a direct member of a specific object, but a variable of another function. log (this) ;}; innerfunc. call (this) ;}}; obj. func (); // output "OBJ in scope" // output "OBJ in scope )"
EXT scope Configuration
As you can see, there is no function with scope assigned, and itsThis"Points to the browser's window object (such as the event handle event handler), unless we changeThisPointer. Among many ext classesScopeIs a configuration that can bind pointers. For relevant examples, see Ajax. Request.
EXT's createdelegate Function
* In addition to the built-in call/apply method, ext also provides the -- auxiliary method for us.Createdelegate. The basic function of this function is to bindThisPointer but not immediately executed. Input a parameter. The createdelegate method ensures that the function runs in the scope of this parameter. For example:
VaR OBJ = {tostring: function () {return 'obj's range (in scope) ';}, // rewrite the tostring function to facilitate console execution. log (this) Output FUNC: function () {// The function here is directly subordinate to the object "object" console. log (this); var innerfunc = function () {// n the function here is not a direct member of a specific object, but a variable of another function. log (this) ;}; innerfunc = innerfunc. createdelegate (this); // here we use the delegate function to overwrite the original function. Innerfunc (); // call the function according to the general syntax}; obj. func (); // output "OBJ in scope" // output "OBJ in scope )"
This is a small example. Its principle is very basic and I hope it can be well digested. Even so, in practical work, we are still confused, but basically, if we can analyze the ins and outs according to the above theoretical knowledge, we will not leave them alone.
In addition, let's take a look at the following example:
Varsds. Load ({callback: function (Records) {col_length = varsds. getcount (); // is the vards out of scope? // Col_length = This. getcount (); // is this equal to store? For (VAR x = 0; x <col_length; X ++) {colarray [x] = varsds. getat (x). Get ('hex ');}}});
But it can be written more clearly:
VaR OBJ = {callback: function (Records) {col_length = varsds. getcount (); // is the vards out of scope? // Col_length = This. getcount (); // is this equal to store? //...}; Varsds. Load (OBJ );
Now the callback function is directly mounted to OBJ, so this pointer is equal to OBJ.
But note:: This is useless. Why? Because you do not know what will happen when obj. Callback is executed. Imagine the load method of Ext. Data. Store (implementation of imitation ):
... Load: function (config) {var o = {}; O. Callback = config. Callback; // load O. Callback ();}...
In this counterfeit implementation, the callback function has the scope of the private variable "O ". Generally, you cannot know how a function is called. If the scope is not declared, you may not be able to use this parameter in the callback function.
Nested functions (scope chain)
When nesting a function, you must note that the scope chain actually changes, which may not seem intuitive. You can put the following code into the firebug monitoring value changes.
VaR testvar = 'window attribute'; var O1 = {testvar: '1', fun: function () {alert ('o1: '+ this. testvar + '<') ;}}; var O2 = {testvar: '2', fun: function () {alert ('o2: '+ this. testvar) ;}}; o1.fun (); // output: O1: 1 <o2.fun (); // output: O2: 2o1. fun. call (O2); // output: O1: 2 <
This is the first example in this article.
VaR testvar = 'window attribute'; var O3 = {testvar: '3', testvar2: '3 ** ', fun: function () {alert ('o3: '+ this. testvar); // 'obj3' var inner = function () {alert ('o3-inner: '+ this. testvar); // 'window attribute 'alert ('o3-inner: '+ this. testvar2); // undefined (undefined)}; Inner () ;}}; o3.fun ();
Here we have changed other functions. This function is almost similar to the original function, but the difference is the writing of internal functions. It should be noted that the scope of the internal function Runtime is different from that of the external function. EXT allows you to specify the function scope when calling a function to avoid scope problems.
Variable Declaration
When initializing a variable, you must add the "Var" keyword. If not, this is a global variable. For example, in the following example, a variable is written inside the function. However, you only intend to declare a local variable, but it may also overwrite the value of the global variable. On the firebug "dom" tab, you can check "window" to view all global variables. If you find that there is a "K" or "x" variable, it proves that you have allocated this variable to an inappropriate scope. See the following example:
VaR I = 4; var J = 5; var K = 7; var fn = function () {var I = 6; k = 8; // note that there is no var before. Therefore, 8 is assigned to variable k! Alert (I); // 6 alert (j); // 5 alert (K + '-1'); // 8-1 x = 1; // This statement has two functions: create all variables X or overwrite all variables X}; FN (); alert (K + '-2 '); // 8-2 (note not 7-2)
It does not change much from the previous example. In addition, note that there is no var keyword before K in the function, so the local variable is not declared here, instead, it allocates a value to the global variable k. In addition, during the alert method execution, parameter I is a local variable that can be found currently, and its value is 6. However, if parameter J cannot be found in the current scopeScope chain)Search up until the J of the global variable is found.
Specify the scope in ext
As mentioned above, ext can flexibly handle the issue of scope when calling a function. Some of the content comes from DJ posts.
When calling a function, you canThisImagine a special (hidden) parameter in each function. At any time, JavaScript willThisPut it inside the function. It is based on a very simple idea: If a function is directly a member of an objectThisIs the object. If the function is not a member of an objectThisIs set to a global object (commonly, window objects in browsers ). The following internal functions clearly show this idea.
If a function is assigned to a variable, that is, it does not belong to a member of any objectThisThe parameter is changed to a Windows Object. The following is an example, which can be directly pasted to the firebug console:
VaR OBJ = {tostring: function () {return 'obj's range (in scope) ';}, // rewrite the tostring function to facilitate console execution. log (this) Output FUNC: function () {// The function here is directly subordinate to the object "object" console. log (this); var innerfunc = function () {// n the function here is not a direct member of a specific object, but a variable of another function. log (this) ;}; innerfunc () ;}}; obj. func (); // outputs "OBJ in the scope (in scope)" // outputs some related content of "window..."
By default, a parameter is called like this-but you can also manually change it.ThisParameters, but the syntax is slightly different. Change "obj. func ();" in the last row:
OBJ. func. Call (window); // output "window-related content..." // output "window-related content ..."
As shown in the preceding example,CallIt is actually another function (method ).CallIt is a built-in method of obj. func. (according to the characteristics of JavaScript, a function is an object .).
Change this wayThisScope. We can continue to use an example to modify the scope of innerfunc.ThisParameter, -- pointing to "Incorrect:
VaR OBJ = {tostring: function () {return 'obj's range (in scope) ';}, // rewrite the tostring function to facilitate console execution. log (this) Output FUNC: function () {// The function here is directly subordinate to the object "object" console. log (this); var innerfunc = function () {// n the function here is not a direct member of a specific object, but a variable of another function. log (this) ;}; innerfunc. call (this) ;}}; obj. func (); // output "OBJ in scope" // output "OBJ in scope )"
EXT scope Configuration
As you can see, there is no function with scope assigned, and itsThis"Points to the browser's window object (such as the event handle event handler), unless we changeThisPointer. Among many ext classesScopeIs a configuration that can bind pointers. For relevant examples, see Ajax. Request.
EXT's createdelegate Function
* In addition to the built-in call/apply method, ext also provides the -- auxiliary method for us.Createdelegate. The basic function of this function is to bindThisPointer but not immediately executed. Input a parameter. The createdelegate method ensures that the function runs in the scope of this parameter. For example:
VaR OBJ = {tostring: function () {return 'obj's range (in scope) ';}, // rewrite the tostring function to facilitate console execution. log (this) Output FUNC: function () {// The function here is directly subordinate to the object "object" console. log (this); var innerfunc = function () {// n the function here is not a direct member of a specific object, but a variable of another function. log (this) ;}; innerfunc = innerfunc. createdelegate (this); // here we use the delegate function to overwrite the original function. Innerfunc (); // call the function according to the general syntax}; obj. func (); // output "OBJ in scope" // output "OBJ in scope )"
This is a small example. Its principle is very basic and I hope it can be well digested. Even so, in practical work, we are still confused, but basically, if we can analyze the ins and outs according to the above theoretical knowledge, we will not leave them alone.
In addition, let's take a look at the following example:
Varsds. Load ({callback: function (Records) {col_length = varsds. getcount (); // is the vards out of scope? // Col_length = This. getcount (); // is this equal to store? For (VAR x = 0; x <col_length; X ++) {colarray [x] = varsds. getat (x). Get ('hex ');}}});
But it can be written more clearly:
VaR OBJ = {callback: function (Records) {col_length = varsds. getcount (); // is the vards out of scope? // Col_length = This. getcount (); // is this equal to store? //...}; Varsds. Load (OBJ );
Now the callback function is directly mounted to OBJ, so this pointer is equal to OBJ.
But note:: This is useless. Why? Because you do not know what will happen when obj. Callback is executed. Imagine the load method of Ext. Data. Store (implementation of imitation ):
... Load: function (config) {var o = {}; O. Callback = config. Callback; // load O. Callback ();}...
In this counterfeit implementation, the callback function has the scope of the private variable "O ". Generally, you cannot know how a function is called. If the scope is not declared, you may not be able to use this parameter in the callback function.