One of the fundamental cores of the scope chain –JS

Source: Internet
Author: User

JSIn the scope, we all know, divided into global scope and local scope, there is no block-level scope, it sounds very simple, but whether the scope can have a deep understanding of the JS code logic to write the success rate, BUG the ability to solve, and whether to write more excellent code, Have a very important impact, if you want to write more elegant and more efficient logic code, then you need to understand the scope of the problem, to be precise, is to have a deeper understanding of how to more effectively and skillfully use the scope.

Global and local scopes

This I think, as long as you learn the programming language, you will have a simple understanding of these. For example, in a JS language, window properties and methods that belong to objects can be accessed locally by our custom functions or methods, and the properties and methods within our custom functions and objects can only be used internally. Here, the window object is in the global scope, and our custom function or inside of the object is the local scope.

    • var num = 1;
    • function Changenum () {
    • var str = "Zhang";
    • num = 2;
    • }
    • Console.log (num); //1
    • Console.log (typeof str); //undefined
    • Changenum ();
    • Console.log (num); //2
    • Console.log (typeof str); //undefined

In the code above, the reason typeof str for this is that the browser throws an error for a variable that is not defined, and blocks the browser from continuing with subsequent code.

Note:If you're sure you want to define a local variable, don't forget to use the var operator.

The position of local scope is usually inside the function or object, for convenience of narration, the next step is to analyze the local scope of the function.

Using var an operator in a function to define a variable, the variable is destroyed when the function is executed (and in some cases not, such as closures, which are explained later), and global variables persist. So when we write code, using as few global variables as possible, abusing global variables, is a disgusting habit, because it brings a lot of unnecessary trouble.

    • 1: Too many variables, name trouble
    • 2: Local variables, forget to use the VAR definition, modify the global variables, such errors for the maintenance of the code is a nightmare
    • 3: Global variables will persist until the page is unloaded, wasting unnecessary memory.

For the time being think of these, anyway is as little as possible to use the right ....

Scope chain

Citation Javascript Advanced Programming (Third Edition) ( P73 ): Contemporary code when executed in an environment, creates a scope chain (scope chain) of the variable object. The purpose of a scope chain is to ensure an orderly access to all variables and functions that the execution environment has access to. The front end of the scope chain, which is always the variable object for the environment in which the code is currently executing. If the environment is a function, its active object is used as a variable object.

Each function has its own execution environment, and when execution flows into a function, the function environment is pushed into an environment stack, and after the function executes, the stack ejects its environment and returns control to the previous execution environment, which is also the scope chain.

The above is written so much that I can look at the following simple code to express:

    • var a = 1;
    • Global scope, which can only access global variables, that is, a variable
    • function A () {
    • var B = 2;
    • The local scope of the//A function, which can be accessed to a B variable, but not to the C variable
    • function B () {
    • //b function Local scope, can access to a,b,c variable
    • var c = 3;
    • }
    • }

Obviously, there is nothing to say about the seemingly scoped aspect. However, sometimes we have to visit something inside the local scope, such as two module functions, using the same data, here we can only put these same data into global variables, so that two function modules, can call this data.

But think, if such a lot of demand, then soon need a lot of a lot of global variables, and abuse of the bad of global variables, the front also said, so this is not a good way of writing.

Reduce global variables

There are many ways to reduce global variables, such as putting some global variables of the same type into an object, then you can turn these types of n multiple global variables into a global object and then access them by object.

Of course, I think, the simplest, the easy to use, or inside a function, continue to define the function, as before in the function, A define the function B , so that we only need a function A of execution, we can complete a whole logic. Internal calls can only be called local variables, and only one function is added globally A .

Like what:

    • function A () {
    • var arr = [];
    • function A () {};
    • Function B () {};
    • Return
    • }

In this way, we would have needed three global variables to become the only one. Of course, there are many ways to reduce global variables, and there is no discussion here.

Here, we discuss one of our most common methods, but also a very common code writing method, it is called: closure.

Reduce global variable methods – closures

When it comes to closures, let's first look at one of the most simple examples, the most basic example: for multiple identical elements, binding events, when clicking on each element, the cue is clicked on the position of the element.

    • <div id = "TEST" >
    • <p> column 1</p>
    • <p> column 2</p>
    • <p> column 3</p>
    • <p> column 4</p>
    • </div>

Such a structure

  • function Bindclick () {
  • var ALLP = document.getElementById ("Test"). getElementsByTagName ("P"),
  • I=0,
  • len = allp.length;
  • for (; i<len;i++) {
  • Allp[i].onclick = function () {
  • Alert ("You click the" +i+ "P tag!");
  • //you Click the 4 P tag!
  • }
  • }
  • }
  • Bindclick ();
  • Run a function, bind a point-and-click event

This kind of JS processing seems to be fine, but in testing, no matter which tag we click p , we get the same results, tell me why? Plainly, this is the scope to cause a problem.

Let's look at the reasons below. First of all, let's JS break down the above code to make it look easier to understand.

    • function Bindclick () {
    •     var ALLP = document.getElementById ("Test"). getElementsByTagName ("P"),
    •          i=0,
    •         len = allP.length;
    •     
    •     for (; i<len;i++) {
    •          allp[i].onclick = ALERTP;
    • &NBSP;&NBSP;&NBSP;&NBSP;}
    •     function ALERTP () {
    •          alert ("You click the" +i+ "P tag!");
    • &NBSP;&NBSP;&NBSP;&NBSP;}
    • }
    • bindclick ();
    • //run function, bind a fixed-point click event

There should be no problem here, the previous use of an anonymous function as click the callback function of the event, a non-anonymous function used here, as a callback, the exact same effect. You can also do the next Test Oh.

Understanding the above, then it can be very simple to understand why our previous code, will get the same result. First look at the for loop, here we just add a callback function for each matching element click , and the callback function is a AlertP function. Here, when a value is added for each element, click i it becomes the number of matching elements, that is, when we trigger the event, that is, when we click on the i=len corresponding element, we expect that the element we clicked is arranged in the first few, this time, clickEvent Trigger, execute callback function AlertP , but when executing here, alert there is a variable in the discovery method is unknown, and in AlertP the local scope, also did not find the corresponding variable, then according to the scope chain to find the way to the parent scope to find, There is a variable in the parent scope here, i and the value of I is the for value after the loop i=len . So there was the effect that we initially saw.

Understand the reason here, then the solution is very simple, the problem of controlling this scope, in short, also a method, that is, in the callback function, with a local variable, to record this i value, so that when the local scope to use the i variable, The value of the variable in the local variable is used preferentially i . No more global variables to look for.

So, understanding the two paragraphs, then if I write the code in the following style:

    • function Bindclick () {
    • var ALLP = document.getElementById ("Test"). getElementsByTagName ("P"),
    • I=0,
    • len = allp.length;
    • for (; i<len;i++) {
    • Allp[i].onclick = ALERTP;
    • }
    • }
    • function ALERTP () {
    • Alert ("You click the" +i+ "P tag!");
    • }
    • Bindclick ();
    • Run a function, bind a point-and-click event

Analysis, if this code is written like this, then what will the result be?

Speaking of which, we can probably understand the concept of closures, according to the scope chain we said before, when a function is running, the function will be pushed into the front of the scope chain, when the function execution ends, the function will be introduced scope chain, and destroy the function inside the local changes and methods.

But here, when the bindClick run is over, you can still click access the I variable inside the function through the event, stating that the bindClick bindClick variables inside the function are i bindClick not destroyed after the end, which is the closure.

2014.10.19-ps:Found above this code, is problematic, such a notation, at run time, I will always be the value of undefined, because at this time, I is in the ALERTP internal and global scope to find, and these two scopes, and there is no definition of I, the correct wording, in the article after the description, So now I can't imagine why I wrote it. Sweat One ~ ~ PS:Closures, in other words, is the end of the function execution, the scope chain after the function pops up, some variables or methods inside the function, can also be referenced by other methods.

OK, back to the point, since it is necessary to know the value of a local variable i , you can solve the problem, then the method is very simple, as we said before, the variable according to accessibility, only into global variables and local variables, then here is very simple, using a function, A local variable can be constructed.

Method 1: Make click the target object and variable I of the bound event become local variables. You can simply pass the two as formal parameters to another function.

  • function Bindclick () {
  • var ALLP = document.getElementById ("Test"). getElementsByTagName ("P"),
  • I=0,
  • len = allp.length;
  • for (; i<len;i++) {
  • ALERTP (Allp[i],i);
  • }
  • function ALERTP (obj,i) {
  • Obj.onclick = function () {
  • Alert ("You click the" +i+ "P tag!");
  • }
  • }
  • }
  • Bindclick ();

Here, obj and i AlertP inside the function, is the local variable. clickthe callback function of the event, although there is still no i value of the variable, but its parent scope AlertP of the internal, but there is a normal display, where AlertP I put in the bindClick interior, just because this can reduce the necessary global functions, and put to the global also does not affect.

Here is the addition of a function to bind, if I do not want to add a function, of course, can also be implemented, here is the self-executing function. Speaking of self-executing function, do not know what people understand, there was an incident, I really do not understand that kind of writing, why is called self-executing function, here also by the way.

There is no one that JS will bind the event when it first comes into contact:obj.onclick = callback();

And then went wrong and couldn't find the error where, later, when a function name is added after the parentheses, the function is executed, then it is understood that the above notation, in fact, is the callback function after the execution of the returned result as the obj click callback function of the event.

and the function name, that is, a function function of the reference bar, according to the function name to find the corresponding function processing module, so it is very easy to think of, the self-executing function is directly after an anonymous function to add a pair of parentheses, then this anonymous function will be executed by itself. So it's a self-executing function.

For example, after the page load, we want to prompt the user immediately, the page is loaded, we are accustomed to write:

    • function loadsuccess () {
    • Alert ("page onload success!");
    • }
    • Loadsuccess ();

This is a common approach, where you first define a function, name the function, and loadSuccess then call the function. Very often very simple.

Here we can also use self-executing functions to complete this hint, and you can write:

    • (function () {
    • Alert ("page onload success!");
    • })();

Complete the same function, you must place this anonymous function inside the parentheses, or the browser will error.

The reason is also JS one of the common sense, that is, the function A(){} method of defining the function, will be in the browser to pre-compile the time to parse, and var A = function(){} such a method of defining the function, when JS resolved to the line code, will be resolved.

Here, if in the self-executing function above, do not add the first parenthesis, the browser will be precompiled, the part of the resolution, but at this time, because this part is not function named, the browser will be pre-compile error, and can not go on.

Using the following function, it can be proved that at the time of pre-compilation, the error is caused by the failure to execute

    • Alert ("123");
    • function () {
    • Alert ("page onload success!");
    • }();

Of course, parentheses are not necessary, for example, when we use expressions to define functions, var A = function(){} this is not done at pre-compilation time, so if our self-executing function defines the return value to another variable, it is possible to omit the parentheses.

Like what:

    • Alert ("123");
    • var a = function () {
    • Alert ("page onload success!");
    • }();

This write will be two consecutive alert execution, complete the function we said before, and will not error, just then, the self-executing function is no return value, so the last a variable, is undefined . However, for the sake of unification, but also in order to look at the convenience, so the various ways of writing self-executing functions, all add parentheses.

As for why, add the parentheses ()() , so write, that is, that is because, this way of writing becomes an expression ....

You can prove it this way:

    • (function A () {
    • Alert ("page onload success!");
    • });
    • A ();

Just like this, and the expression definition function is similar, and there is also a problem is that the A function, only in the parentheses inside the use. For external use, it is necessary to assign the expression to a value, and if it is assigned, it is not a function defined using an assignment expression.

Said a little farther, back to continue: here also probably understand the self-executing function of the execution method. The method of using self-executing functions, the binding of events, presumably can also guess the principle of it. obj.onclick = callback();. If I callback define the return value of a function as a function, then the click return function is not triggered when the event is triggered.

So, we can write this:

    • function Bindclick () {
    • var ALLP = document.getElementById ("Test"). getElementsByTagName ("P"),
    • I=0,
    • len = allp.length;
    • for (; i<len;i++) {
    • Allp[i].onclick = ALERTP (i);
    • }
    • }
    • function ALERTP (i) {
    • return function () {
    • Alert ("You click the" +i+ "P tag!");
    • }
    • }
    • Bindclick ();

There's nothing wrong with that? It should be easy to understand.

But this way of writing, added a function variable, if not added ... OK, just replace the back function with the past ....

  • function Bindclick () {
  • var ALLP = document.getElementById ("Test"). getElementsByTagName ("P"),
  • I=0,
  • len = allp.length;
  • for (; i<len;i++) {
  • Allp[i].onclick = function (i) {
  • return function () {
  • Alert ("You click the" +i+ "P tag!");
  • }
  • } (i);
  • }
  • }
  • Bindclick ();

So it seems that the comparison of the previous writing, it should be able to clearly understand why this is written, you can get the results we want.

OK, this is the simplest closure of the application, the other closure of the writing also has, but in principle, and above this is the same principle, so here is not listed, used in the closure of the place is actually a lot (such as lazy loading function, the object definition in singleton mode, etc.), If you can understand the principle of the simplest closure, then the rest of the use of the closure of the place, see, will be able to understand. Or, when you want to use it, you can think about how it should be used.

In the previous article, there is also an article in the code, mainly the use of the idea of closure, you can refer to: jquery source Learning (ii) –proxy

Note

Timers in some dynamic pages, do some animation effect, is an indispensable element, it is the same as the alert method, all belong to window the method of the object. There are a few differences when using timers, so here's a setTimeout simple example:

See example: What are the results of the two executions in the code setTimeout ?

    • var a = 1;
    • function B () {
    • var a = 2;
    • SetTimeout ("C ()", 1000);
    • SetTimeout (c,2000);
    • function C () {
    • Alert ("a=" +a);
    • }
    • }
    • function C () {
    • Alert ("a=" +a);
    • }
    • B ();

Test it will know, respectively, 1 and 2 , because setTimeout it is the next execution of the method, the first way of writing, will only find the global variables, whether there are A functions, and the second way of writing, will first find whether there is a function in the current scope A , if not local, The order is found in the global scope.

There is a situation, that is, the function of the internal invocation of the this point, is pointed to window , here can be said to be wrong, it can be said that is true, see an example: Assume id=test that an element is bound to an click event. View the values in them this .

    • document.getElementById ("Test"). onclick = function () {
    • alert (this); //point to the element object that triggered the event
    • SetTimeout ("A ()", 1000); //Call to window here
    • }
    • function A () {
    • alert (this);
    • }

This is not considered in IE8- the browser.

In the case of the first two timers, write the following code:

    • document.getElementById ("Test"). onclick = function () {
    • alert (this); //point to the element object that triggered the event
    • SetTimeout (a,1000); ////here still points to window
    • function A () {
    • alert (this);
    • }
    • };
    • function A () {
    • alert (this);
    • }

Why? Isn't it supposed that this should be the internal method of the call A ? Why this is it pointing to window ?

There is an uncertain idea that when a timer is invoked, the method within the current scope is pointed to the this window object. And just modify the direction of the method inside this , if there is a private variable value, still according to the original function location, according to the scope of the value.

You can prove it this way:

    • var a = 1;
    • document.getElementById ("Test"). onclick = function () {
    • alert (this);
    • var a = 123;
    • SetTimeout (a,1000);
    • function A () {
    • Alert ("a=" +a);
    • alert (this);
    • }
    • }
    • function A () {
    • Alert ("a=" +a);
    • alert (this);
    • }

thisThe pointer is the same as the previous instance, but the value alert in the a variable is the first to get the value in the local scope.

Of course, if you change the call method in the timer, the result will be different.

    • var a = 1;
    • document.getelementbyid ("Test"). onclick = function () {
    •     alert ( this);
    •     var a = 123;
    •     settimeout ("A ()", +);
    •     function A () {
    •          alert ("a=" +a);
    •         alert (this);
    •     }
    • function A () {
    •     alert ("a=" +a);
    •     alert (this);

Here, it is interesting to try it, and here, it is also found that, although the use of timers will force the internal direction of the calling function this to change the direction window of the exponentially, but the impact on the scope chain is only a different effect. That is: setTimeout("A()",1000); and setTimeout(A,1000); the difference. Of course, for the second kind of writing, we can use call and apply forcibly change A this the direction of the internal, but these with the content of this article, it seems that there is no relationship, not much to say.

In fact, according to my original idea, here is the time to write a timer ( setTimeout,setInterval ) and call , the apply relationship between these and the scope chain, but write here, and feel that they do not have any relationship, so about the scope chain, here.

OK, if you have any new ideas, or know, or find errors in the text, please advise, thank you very much!

This address: http://www.zhangyunling.com/?p=134

One of the fundamental cores of the scope chain –JS

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.