Deep understanding of JavaScript scope and variable elevation _javascript techniques

Source: Internet
Author: User

What is the result of the following program?

Copy Code code as follows:

var foo = 1;
function Bar () {
if (!foo) {
var foo = 10;
}
Alert (foo);
}
Bar ();

The result is 10;

What about the bottom one?

Copy Code code as follows:

var a = 1;
Function B () {
A = 10;
Return
function A () {}
}
b ();
alert (a);

The result is 1.

Did I scare you? What's going on? This may be unfamiliar, dangerous, confusing, and, in fact, a very useful and impressive JavaScript language feature. I don't know if there's a standard name for this behavior, but I like the term: "Hoisting (variable elevation)". This article will give a tip on this mechanism, but first let's have some necessary understanding of the scope of JavaScript.

The scope of JavaScript

One of the most confusing places for JavaScript beginners is the scope; in fact, not just beginners. I've seen some experienced JavaScript programmers, but they don't understand scope very deeply. The JavaScript scope is confusing because the program syntax itself is as long as the C-family language, like the following C program:

Copy Code code as follows:

#include <stdio.h>
int main () {
int x = 1;
printf ("%d,", x); 1
if (1) {
int x = 2;
printf ("%d,", x); 2
}
printf ("%d\n", X); 1
}

The output is 1 2 1, because the C family language has a block scope, and when the program control walks into a block, such as an if block, the variable that acts only on that block can be declared without affecting the scope outside the block. But in JavaScript, that's not going to work. Look at the following code:
Copy Code code as follows:

var x = 1;
Console.log (x); 1
if (true) {
var x = 2;
Console.log (x); 2
}
Console.log (x); 2

The result would be 1 2 2. Because JavaScript is a function scope. This is the biggest difference with the C family language. The IF in the program does not create a new scope.

For many C,c++,java programmers, this is not what they expect and welcome. Fortunately, based on the flexibility of JavaScript functions, there are flexible places to be. If you have to create a temporary scope, you can do the following:

Copy Code code as follows:

function foo () {
var x = 1;
if (x) {
(function () {
var x = 2;
Some other code
}());
}
X is still 1.
}

This approach is flexible and can be used wherever you want to create a temporary scope. Not just inside the block. However, I highly recommend that you take the time to understand the scope of JavaScript. It's very useful and is one of my favorite JavaScript features. If you understand the scope, then variable elevation is more meaningful to you.

Variable declarations, naming, and promotion

In JavaScript, variables come into scope in 4 basic ways:

·1 language built-in: All scopes have this and arguments; (Translator note: Tested arguments is not visible in the global scope)

• 2 form parameter: The formal parameter of a function is a part of the function body scope;

• 3 function declaration: Like this form: function foo () {};

• 4 variable declaration: like this: Var foo;

function declarations and variable declarations are always silently "elevated" by the interpreter to the top of the method body. This means, like the following code:

Copy Code code as follows:

function foo () {
Bar ();
var x = 1;
}

Would actually be interpreted as:
Copy Code code as follows:

function foo () {
var x;
Bar ();
x = 1;
}

Whether or not the block that defines the variable can be executed. The following two functions are actually one thing:
Copy Code code as follows:

function foo () {
if (false) {
var x = 1;
}
Return
var y = 1;
}
function foo () {
var x, y;
if (false) {
x = 1;
}
Return
y = 1;
}

Note that the variable assignment has not been promoted, except that the declaration has been promoted. However, the declaration of a function is somewhat different, and the function body is also promoted together. Note, however, that there are two ways in which a function can be declared:
Copy Code code as follows:

function Test () {
Foo (); TypeError "Foo is not a function"
Bar (); "This'll run!"
var foo = function () {//variable point to functional expression
Alert ("This won ' t run!");
}
function bar () {//function declaration functions named Bar
Alert ("This'll run!");
}
}
Test ();

In this example, only functional declarations are promoted along with the function body. The declaration of Foo is promoted, but the body of the function it points to is only assigned at execution time.

The above covers some of the basics of ascension, and they don't seem so confusing. However, in some special scenes, there is a certain degree of complexity.

Variable parsing order

The most need to keep in mind is the variable parsing order. Remember the 4 ways I gave you the name to enter the scope? The order in which the variables are parsed is the order in which I list them.

Copy Code code as follows:

<script>
function A () {
}
var A;
alert (a);//print out a function body
</script>

<script>

var A;
function A () {
}
alert (a);//print out a function body
</script>
But pay attention to the distinction and the following two:
<script>
var a=1;
function A () {
}
alert (a);//Print out 1
</script>

<script>
function A () {
}

var a=1;

alert (a);//Print out 1
</script>


Here are 3 exceptions:

1 The built-in name arguments behaves strangely, he should appear to be declared after the function form argument, but before the function declaration. This is to say that if there is a arguments in the formal parameter, it will have precedence over the built-in one. This is a very bad feature, so to eliminate the use of arguments in the formal parameters;

2 It is a good feature to define this variable in any place with grammatical errors;

3 If multiple formal parameters have the same name, the last one has priority, even if the actual operation of its value is undefined;

Named functions

You can give a function a name. In this case, it is not a function declaration, and the function body definition of the specified function name (if any, such as the following spam, the translator) will not be promoted, but ignored. Here are some code to help you understand:

Copy Code code as follows:

Foo (); TypeError "Foo is not a function"
Bar (); Valid
Baz (); TypeError "Baz is not a function"
Spam (); Referenceerror "spam is not defined"

var foo = function () {}; Foo point to anonymous function
function bar () {}; function declaration
var baz = function spam () {}; Named functions, only Baz are promoted and spam are not promoted.

Foo (); Valid
Bar (); Valid
Baz (); Valid
Spam (); Referenceerror "spam is not defined"


How to write code

Now that you understand the scope and the variable elevation, what does this mean for JavaScript encoding? The most important point is that you always define your variables with var. And I strongly recommend that for a name, there will always be a VAR declaration within a scope. If you do this, you will not encounter scope and variable elevation issues.

What does the language specification say?

I find that ECMAScript reference documents are always useful. Here's what I found about scope and variable elevation:

If a variable is declared in the function body class, it is a function scope. Otherwise, it is the global scope (as a property of global). The variable will be created when execution enters the scope. A block does not define a new scope, and only function declarations and programs (the translator thinks that code execution of a global nature) creates new scopes. Variables are initialized to undefined when they are created. If a variable declaration statement contains an assignment operation, the assignment action occurs only when it is executed, not when it is created.

I expect this article to bring a glimmer of light to programmers who are more puzzled by JavaScript. I also do my best to avoid the temptation to bring more confusion. If I say something wrong, or ignore something, please let me know.

Translator Supplement

A friend reminded me that I found the promotion of named functions under the global scope under IE:

I was testing this when I translated the article:

Copy Code code as follows:

<script>
Functiont () {
Spam ();
var baz = function spam () {alert (' is spam ')};
}
T ();
</script>

This kind of writing, namely the promotion of the name function under the non global scope, is consistent in IE and ff. I changed it to:
Copy Code code as follows:

<script>
Spam ();
var baz = function spam () {alert (' is spam ')};
</script>

Then IE can be executed under the spam, FF can not. Explains that different browsers differ in the handling of this detail.

This question also led me to think about another 2 questions, 1: For the global scope variable, VAR is different from Var. No var is written, and its variables are not promoted. For example, the following two programs, the second will be an error:

Copy Code code as follows:

<script>
alert (a);
var a=1;
</script>

Copy Code code as follows:

<script>
alert (a);
A=1;
</script>

The local variables created in the 2:eval are not promoted (nor can it be done).
Copy Code code as follows:

<script>
var a = 1;
function T () {
alert (a);
Eval (' var a = 2 ');
alert (a);
}
T ();
alert (a);
</script>

Related Article

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.