Scope of JavaScript

Source: Internet
Author: User

Reprint: http://www.cnblogs.com/qixuejia/archive/2009/12/18/1626951.html

The scope of JS is divided by functions, not blocks.

Example

1 vararg = "arg";2 3 if(true) {//This is the definition in the block, and this is the global variable4     vararg = "New arg";5 }6Console.log (arg = = "new arg");//true;7 8 functionFun () {9     vararg = "Old arg";//This is the definition in the function, this is the local variableTen } One  A Fun (); -Console.log (arg = = "new arg");//True;too hasn't changed .

All variables that are part of the global scope are properties of the Window object

The first line of ARG in the above example is equal to Window.arg

Example

1 function Fun () {2     arg = "Test"; 3 }4fun(); 5 6 // true

Scope (scope) is one of the cornerstones of the JavaScript language and can be the most troubling thing to build complex programs. I can't remember how many times I passed the control between functions forget which object the This keyword refers to, and even, I often in a variety of chaotic ways to the national salvation, trying to disguise as normal code, in my own understanding of the way to find the variables needed to access.

This article will address this problem in a positive way: A brief description of the context and scope of the definition, analysis allows us to control the context of the two methods, and finally into an efficient solution, it can effectively solve the problem I encountered 90%.

Where am I? Who are you again?
Each byte of a JavaScript program is executed in this or that run context (execution context). You can think of these contexts as neighbors of code, and they can give each line of code a way to indicate where the friend and neighbor are from. Yes, this is a very important message, because JavaScript society has a fairly strict set of rules for who to associate with. The running context is a gated community rather than a small open door.

We can often refer to these social boundaries as scopes and have sufficient importance to legislate in each neighbor's charter, which is the scope chain (scope chain) of the context we want to say. Within a particular neighborhood, the code can only access variables within its scope chain. The code prefers to work locally (local, or local) compared to variables beyond its neighborhood.

Specifically, executing a function creates a different run context, which increases the local scope to within the scope chain it defines. javascript resolves identifiers in a specific context by the local-to-global ascent of the scope chain. This means that this level of variables takes precedence over variables that have the same name at the top level within the scope chain. Obviously, when my friends talk about "Mike West" (the original author of this article), they are talking about me, not bluegrass singer or Duke professor, although the two are much more famous.

Let's look at some examples to explore these meanings:

<script type= "Text/javascript" >
var ima_celebrity = "Everyone can see me! I ' m famous! ",
the_president = "I ' m The decider!";

function Pleasantville () {
var the_mayor = "I rule Pleasantville with an iron fist!",
Ima_celebrity = "All my neighbors know who I am!";

function Lonely_house () {
var agoraphobic = "I fear the day star!",
A_cat = "Meow.";
}
}
</script>

Our All-Star, ima_celebrity, household name (everyone knows her). She is politically active and dares to shout the president (ie the_president) at a fairly frequent grassroots level. She will sign and answer questions for everyone she meets. That is, she will not have a private connection with her fans. She's pretty well aware of the fans ' existence and has a certain degree of personal life, but it's also certain that she doesn't know what fans are doing or even the fans ' names.

In the Happy City (Pleasantville), the mayor (The_mayor) is well known. She often walks in her town, chatting with her constituents, shaking hands and kissing children. Because the Happy City (Pleasantville) is a big and important neighbour, the mayor puts a red phone in her office, a 7x24 hotline that can pass through the president. She could also see the solitary house on the outskirts of the city (Lonely_house), but never cared who lived there.

And the Solitary House (Lonely_house) is a self-world. Patients often himself in the inside, playing cards and feeding a kitten (a_cat). He occasionally calls the mayor (The_mayor) for some local noise control, and even writes some fan words to her when he sees ima_celebrity in local news (of course, this is the ima_celebrity in Pleasantville).

This? Is that a shrimp?
Each run context provides a keyword named this, in addition to creating a scope chain. Its general usage is that this is a unique feature that provides a way for the neighborhood to access it. But always relying on this behavior is unreliable: depending on how we enter a particular neighborhood, this is probably something else. In fact, how we go into the neighbor's house is usually exactly what this means. There are four situations that deserve special attention:

Methods for calling Objects
In classic object-oriented programming, we need to identify and reference the current object. This is a great way to play this role, providing our objects with the ability to find themselves and point to their own properties.

<script type= "Text/javascript" >
var deep_thought = {
The_answer:42,
Ask_question:function () {
return this.the_answer;
}
};

var the_meaning = deep_thought.ask_question ();
</script>


This example establishes an object named Deep_thought, sets its property the_answer to 42, and creates a method named Ask_question. When Deep_thought.ask_question () executes, JavaScript establishes a run context for the call of the function, through the "." The deep_thought operator points this to the referenced object, where it is the object. This method can then find its own property in the mirror through this, returning the value saved in This.the_answer: 42.

constructor function
Similarly, when you define a function that uses the New keyword as a constructor, this can be used to refer to the object you just created. Let's rewrite an example that will reflect this situation:

<script type= "Text/javascript" >
function Bigcomputer (answer) {
This.the_answer = answer;
This.ask_question = function () {
return this.the_answer;
}
}

var deep_thought = new Bigcomputer (42);
var the_meaning = deep_thought.ask_question ();
</script>


Instead of creating a Deep_thought object explicitly, we write a function to create a Bigcomputer object, and instantiate the Deep_thought as an instance variable by using the New keyword. When new Bigcomputer () is executed, a new object is created transparently in the background. After calling Bigcomputer, its this keyword is set to point to a reference to the new object. This function can set properties and methods on this, and eventually it will return transparently after the Bigcomputer executes.

However, it should be noted that the deep_thought.the_question () can still be executed as before. So what's going on here? Why is this different within the the_question and within the bigcomputer? To put it simply, we entered bigcomputer through new, so this represents "new" objects. On the other hand, we enter the_question through Deep_thought, so when we execute the method, this represents "the object referenced by Deep_thought". This is not read from the scope chain just like any other variable, but is reset in context, based on contexts.

Function call
If there is no fantasy of any related object, we just call a common, common function, and in this case what does this mean?

<script type= "Text/javascript" >
function Test_this () {
return this;
}
var i_wonder_what_this_is = Test_this ();
</script>


On such occasions, we do not provide context through new, nor do we secretly provide the context behind it in some form of object. Here, this defaults to referencing the most global things: for Web pages, this is the Window object.

Event handler function
More complex calls than normal functions, let's say we use a function to handle an onclick event. When the event triggers our function to run, what does this show here? Unfortunately, there is no simple answer to this question.

If we are writing inline event handlers, this refers to the Global window object:

<script type= "Text/javascript" >
function Click_handler () {
alert (this); Popup Window Object
}
</script>
...
<button id= ' Thebutton ' onclick= ' Click_handler () ' >click me!</button>


However, if we add an event handler through JavaScript, this refers to the DOM element that generated the event. (Note: The event handling here is very concise and easy to read, but the rest is Shia.) Instead, use the real addevent function):

<script type= "Text/javascript" >
function Click_handler () {
alert (this); The DOM node of the eject button
}

Function AddHandler () {
document.getElementById (' Thebutton '). onclick = Click_handler;
}

Window.onload = AddHandler;
</script>
...
<button id= ' Thebutton ' >click me!</button>


Complex situation
Let's briefly run through this last example. We need to ask deep_thought a question, what happens if you don't run Click_handler directly but by clicking the button? The code to solve this problem seems straightforward, and we might do this:

<script type= "Text/javascript" >
function Bigcomputer (answer) {
This.the_answer = answer;
This.ask_question = function () {
alert (this.the_answer);
}
}

Function AddHandler () {
var deep_thought = new Bigcomputer (42),
The_button = document.getElementById (' Thebutton ');

The_button.onclick = deep_thought.ask_question;
}

Window.onload = AddHandler;
</script>


It's perfect, isn't it? Imagine that we clicked on the button, Deep_thought.ask_question was executed, we also got "42". But why does the browser give us a undefined? Where are we wrong?

The problem is obvious: we pass a reference to Ask_question, which is executed as an event handler, not the same context as the object method to run. In short, the This keyword in ask_question points to the DOM element that generated the event, not to the Bigcomputer object. Dom elements do not have a the_answer attribute, so we get undefined instead of "42″." SetTimeout also has a similar behavior, and it runs into a global context while delaying the execution of the function.

This problem pops up from time to time in all corners of the program, and is a very difficult problem to get out of the way if you don't track every corner of the program, especially if your object has attributes with the same name as the DOM element or Window object.

Use. Apply () and. Call () to control the context
When we click the button, what we really need is to be able to ask deep_thought a question, and further, what we really need is the ability to call the object in its own primitive context when answering events and settimeout calls. There are two little-known JavaScript methods, apply and call, and when we perform function calls we can get the curve to save us the goal, allowing us to manually override this default value. Let's look at call first:

<script type= "Text/javascript" >
var first_object = {
Num:42
};
var second_object = {
Num:24
};

function Multiply (mult) {
return this.num * mult;
}

Multiply.call (First_object, 5); Returns 42 * 5
Multiply.call (Second_object, 5); Returns 24 * 5
</script>


In this example, we first defined two objects, First_object and Second_object, each with their own num attribute. A multiply function is then defined, which takes only one parameter and returns the product of the NUM attribute of the object that this parameter refers to. If we call the function itself, the answer that is returned is probably undefined, because the global window object does not have a num attribute unless it is explicitly specified. We need some way to tell multiply what the This keyword should refer to. And multiply's call method is exactly what we need.

The first parameter of call defines the object of this within the function that has already been executed. The remaining parameters are passed into the function that is already executed, as if the function itself calls. Therefore, when executing Multiply.call (First_object, 5), multiply is called, 5 is passed in as the first parameter, and the This keyword is set to a reference of First_object. Similarly, when you execute Multiply.call (Second_object, 5), 5 is passed in as the first argument, and the This keyword is set to a reference of Second_object.

Apply works in the same way as call, but it allows you to wrap parameters into an array and pass them on to the calling function, which is especially useful when a program generates a function call. Using apply to reproduce the previous piece of code is not really a big difference:

<script type= "Text/javascript" >
...

Multiply.apply (First_object, [5]); Returns 42 * 5
Multiply.apply (Second_object, [5]); Returns 24 * 5
</script>


Both the apply and call itself are very useful and worth storing in your toolkit, but for the context of the event handler changes, it's just a matter of sending the Buddha halfway to the west, and the rest is for us to solve. When we set up the processing function, we naturally think that simply by using call to change the meaning of this:

Function AddHandler () {
var deep_thought = new Bigcomputer (42),
The_button = document.getElementById (' Thebutton ');

The_button.onclick = Deep_thought.ask_question.call (deep_thought);
}


The reason the code is problematic is simple: call executes the function immediately: it can actually be encapsulated with an anonymous function, such as The_button.onclick = function () {Deep_thought.ask_question.call ( Deep_thought), but still less elegant than the bind that is about to be discussed. We give Onclcik the result of a function execution rather than a reference to a function. So we need to take advantage of another JavaScript feature to solve this problem.

The beauty of Bind ()
I'm not a big fan of the Prototype JavaScript framework, but I'm impressed with its overall code quality. Specifically, it adds a neat complement to the function object, which has a significant positive impact on the context of the execution of my management functions call: Bind performs the same common task as called, changing the context of the function execution. The difference is that bind returns the final result of a function reference that can be used instead of the immediate execution of call.

If you need to simplify the bind function to grasp the focus of the concept, we can first insert it into the product example discussed earlier to see how it works. This is a fairly elegant solution:

<script type= "Text/javascript" >
var first_object = {
Num:42
};
var second_object = {
Num:24
};

function Multiply (mult) {
return this.num * mult;
}

Function.prototype.bind = function (obj) {
var method = This,
temp = function () {
return method.apply (obj, arguments);
};

return temp;
}

var first_multiply = Multiply.bind (First_object);
First_multiply (5); Returns 42 * 5

var second_multiply = Multiply.bind (Second_object);
Second_multiply (5); Returns 24 * 5
</script>


First, we define the First_object, second_object, and multiply functions, as always. After careful handling of this, we continue to define a bind method for the prototype of the function object, so that the functions in our program have a bind method available. When executing multiply.bind (First_object), JavaScript creates a run context for the Bind method, puts this as a reference to the multiply function, and puts the first parameter, obj, in the First_object reference. So far, everything is well.

The real genius of this solution is the creation of method, which is referred to as the reference to this (that is, the multiply function itself). The anonymous function of the next line is created, the method is accessed through its scope chain, and obj (do not use this here, because this is overwritten by the new, local context after the newly created function executes). This alias makes it possible for apply to execute the multiply function, while passing obj ensures that the context is correct. In computer science, temp is a closure (closure), which guarantees that the final return of a multiply,bind call that needs to be performed in the context of first_object can be used in any context.

This is what the event handler and settimeout scenarios are really needed. The following code completely solves these problems, binds the Deep_thought.ask_question method to the context of the deep_thought, and therefore works correctly when any event is triggered:

Function AddHandler () {
var deep_thought = new Bigcomputer (42),
The_button = document.getElementById (' Thebutton ');

The_button.onclick = Deep_thought.ask_question.bind (deep_thought);
}

Scope of JavaScript

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.