JavaScript scoping and hoisting translation _javascript tips

Source: Internet
Author: User
Do you know what the following JavaScript code is going to do, and what is the value of alert?
Copy Code code as follows:

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

If the answer is "10" and you're surprised, the following will make you even more confused:
[/code]
var a = 1;
Function B () {
A = 10;
Return
function A () {}
}
b ();
alert (a);
[/code]
The browser will alert "1". So, what's going on? Although this may seem strange, dangerous and somewhat confusing, it is in fact a powerful and expressive feature of the language. I don't know if there is a standard to define this behavior, but I like to use "hoisting" to describe it. This article tries to explain this mechanism, but first, let's do some necessary understanding of the scoping of JavaScript.
Scoping in JavaScript
Scoping is one of the most confusing parts for JavaScript novices. In fact, not only novice, I met or a lot of experienced JavaScript programmers can not fully understand scoping. The reason JavaScript's scoping is so complicated is that it looks very much like a member of the C-system language. Take a look at the C program below:
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 of this program is 1,2,1. This is because in the C-system language there is a block-level scope (Block-level scope), which, when entered into a block, is like an if statement, where a new variable is declared in the block-level scope, which does not affect the external scope. But that's not what JavaScript is. Try the following code in the Firebug:
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

In this code, Firebug displays 1,2,2. This is because JavaScript is a function-level scope (function-level scope). This is completely different from the C-system language. block, just like the IF statement, and does not create a new scope. Only a function creates a new scope.
For most programmers who are familiar with c,c++,c# or Java, this is unexpected and is not being seen. Luckily, because of the flexibility of JavaScript functions, we have a solution for this problem. If you have to create a temporary scope in a function, do it as follows:
Copy Code code as follows:

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

This aspect is indeed very flexible, and it is used in any place where you need to create a temporary scope, not just in a block. However, I strongly recommend that you take the time to understand the JavaScript scoping. It's really strong, and it's one of my favorite language features. If you have a good understanding of scoping, it will be much easier to understand hoisting.
Declarations, Names, and hoisting
In JavaScript, there are four types of names (name) in one scope (scope):
1. Language self definition (language-defined): All scopes will contain this and arguments by default.
2. function parameter (formal parameters): the form of a function with a name enters into the scope of the function body.
3. function declaration (Functions decalrations): Through the form of function foo () {}.
4. Variable declaration (Variable declarations): In the form of Var foo;
function declarations and variable declarations are always implicitly elevated (hoist) by the JavaScript interpreter to the top of the scope that contains them. Obviously, the language itself definition and function parameters are already at the top of the scope. This is like the following code:
Copy Code code as follows:

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

is actually interpreted as following:
Copy Code code as follows:

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

The result is no effect, regardless of whether the declaration was executed. The following two pieces of code are equivalent:
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;
}

Notice that the assigned part of the declaration has not been promoted (hoist). Only the name of the declaration has been promoted. This is different from the function declaration, where the entire function body is also promoted. But keep in mind that there are generally two ways of declaring a function. Consider the following JavaScript code:
Copy Code code as follows:

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

Here, only the way function declarations are raised with the function body, and the function expression only promotes the name, and the function body is only assigned when it executes to an assignment statement.
That includes all the basics of Ascension (hoisting), and it doesn't look that complicated or confusing, does it? However, this is JavaScript, in some special cases, there will always be a little complicated.
Name resolution Order
The most important special case that needs to be remembered is the name resolution order. Remember that a name goes into a scope a total of four ways. The order that I listed above is the order in which they are parsed. In general, if a name is already defined, he will never be overwritten by another name that has no attributes. This means that a function declaration has a higher priority than a variable declaration. But this does not mean that the assignment of the name is invalid, only that the part of the declaration is ignored. But there are a few exceptions:
The built-in name arguments's behavior is a little weird. It seems that after the formal parameter, the function declaration is declared. This means that a arguments named is a higher priority than the built-in arguments, even if the formal parameter is undefined. This is a bad feature and do not use arguments as a formal parameter.
Any attempt to use this as an identity will cause syntax errors, which is a good feature.
If there is more than one parameter with the same name, the formal parameter at the end of the list has the highest precedence, even if it is undefined.
Name Function Expressions
You can define a name in a function expression, just like the statement of a function declaration. But this does not make it a function declaration, and the name is not introduced into the scope, and the function body is not promoted (hoist). Here are some code to illustrate what I mean:
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 () {}; anonymous function expression (' foo ' is promoted)
function bar () {}; function declaration (' bar ' and function body promoted)
var baz = function spam () {}; Named function expression (only ' Baz ' is promoted)
Foo (); Valid
Bar (); Valid
Baz (); Valid
Spam (); Referenceerror "spam is not defined"

How to Code and this knowledge
Now that you understand scope and ascension, what does this mean for writing JavaScript code? The most important one is to always use the Var statement when declaring a variable. I strongly recommend that you use only one var at the top of each scope. If you force yourself to do so, you will never be bothered by the problems associated with Ascension. Although doing so will make it more difficult to keep track of which variables are actually declared in the current scope. I recommend using the Onevar option in JSLint. If you do all of the previous suggestions, your code will look like this:
Copy Code code as follows:

/*jslint onevar:true [...] *
function foo (A, B, c) {
var x = 1,
Bar
Baz = "something";
}

What the Standard Says
I find it always useful to refer directly to ECMAScript Standard (pdf) To understand how these things work. The following is an excerpt of a variable Declaration and scope (Section 12.2.2):
IF The variable statement occurs inside a functiondeclaration, the variables are defined with function-local scope in function, as described in section 10.1.3. Otherwise, they are defined with global scope (which, they are, as members of the global object, as created in Section 10.1.3) using the property attributes {Dontdelete}. Variables are created the execution scope is entered. A blocks does not define a new execution scope. Only the program and Functiondeclaration produce a new scope. Variables are initialised to undefined when created. A variable with A Initialiser is assigned the value of it assignmentexpression when the variablestatement is executed, n OT when the variable is created.

I hope this article will give some hints to the most confusing part of JavaScript programmers. I try to write comprehensively so as not to cause more confusion. If I write wrong or miss something important, please let me know.
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.