Original: http://www.adequatelygood.com/JavaScript-Scoping-and-Hoisting.html
= = = Translation starts = = =
Do you know what the following JavaScript script execution results are?
1 var foo=1; 2 function Bar () {3 if (! foo) {4 var foo=10; 5 }6 alert (foo); 7 }8 Bar ();
If you're surprised that the result of the pop-up is "10", the following script will make you feel dizzy:
1 var a=1; 2 function B () {3 a=10; 4 return ; 5 function A () {}; 6 }7B (); 8 alert (a);
The browser will pop up "1", what the hell is going on? This seems strange, in fact, it is a powerful and expressive feature of language. I don't know if this particular behavior has a standard name, but I like to call it "hoisting." Next I will try to analyze this mechanism, but it is necessary to understand the scope of JavaScript first.
Scopes in JavaScript
For JavaScript beginners, the scope is often confusing to them. In fact, some senior JavaScript developers are not fully aware of scopes. The scope of JavaScript is so confusing because it's a bit like the C language, see the C program below:
1#include <stdio.h>2 intMain () {3 intX=1;4printf ("%d\n", X);//15 if(1){6 intx=2;7printf ("%d\n", X);//28 }9printf ("%d\n", X);//1Ten}
The program outputs 1,2,1 in turn because the C-system language has block-level scopes. When a program runs to a block (such as an if statement), the new variable defined in the block does not affect the outer scope. But not the same in Javsscript, try executing the following script:
1 var x=1; 2 console.log (x); // 1 3 if (true) {4 var x=2; 5 Console.log (x); // 2 6 }7 console.log (x); // 2
After the script executes, the 1,2,2 is output sequentially, because the javsscript has only the function-level scope, which is fundamentally different from the C-system language, and the block (such as the IF statement) does not create a new scope, only the function.
For some developers who use C, C + +, C #, or Java, this is a tough one to accept. Fortunately, the JavaScript function is flexible enough to be used in other workarounds. If you must create a temporary scope within a function, you can do this:
1 functionfoo () {2 varX=1;3 if(x) {4(function(){5 varx=2;6 //Some other code7 }());8 }9 //x is still 1.Ten}
This method is quite flexible and can be used wherever it is needed, not just in block statements. But I strongly recommend that you take some time to really understand and appreciate the scope of JavaScript, which is one of my favorite language features, and it's really very powerful. If you understand the scope, it is easier to understand the declaration ahead of time.
Declaration, variable name, declaration in advance
In JavaScript, a variable can enter a scope in one of the following four ways:
1, language built-in: All scopes default to include "This" and "arguments" variables. 2, function parameters: functions can have formal parameters, the scope of the function is the body. 3, Function declaration: Shape as "function foo () {}" declaration. 4, Variable declaration: Shape as "var foo;" The declaration.
function declarations and variable declarations are always automatically placed at the top of the owning scope by the JavaScript interpreter, and the variables built into the function parameters and language are at the top of the range by default. For example, the following code is available:
1 function foo () {2 Bar (); 3 var x=1; 4 }
Parsed by the parser becomes:
1 function foo () {2 var x; 3 Bar (); 4 X=1; 5 }
This shows that no matter where the statement is placed, it will be executed, such as the following two functions, which are equal:
1 functionfoo () {2 if(false){3 varX=1;4 }5 return;6 varY=1;7 }8 9 functionfoo () {Ten varx, y; One if(false){ AX=1; - } - return; theY=1; -}
It is important to note that sometimes declarations and assignments are written together, but the assignment part is not advanced and only the declaration is advanced. Function declarations are somewhat special, and the entire function body is also advanced. But don't forget that there are two ways to declare a function, see the following code:
1 functionTest () {2Foo ();//TypeError "Foo is not a function"3Bar ();//"This would run!"4 varfoo=function(){//function expression assigned to local variable "foo"5Alert (' This won ' t run! ');6 };7 function Bar () {//function Declaration,given the name8Alert (' ThisWould run! ');9 }Ten } OneTest ();
In this example, only the function declaration using function declarations is advanced to the top, and the function expression is used to assign a value, only the name "foo" is advanced to the top, the function body is not.
The above example basically covers the case of automatic advance, which is not so complicated as to be confusing. Of course, some of the other more specific examples are somewhat complex.
Variable recognition order
We have to remember in particular the order in which the variables are identified, and the previous four ways to enter the scope of the variable names are the order in which they are identified. Typically, if a variable name is already defined, it is not overwritten by a variable of the same name. This means that the function declaration has a higher precedence than the variable declaration, but this does not affect the assignment operation, except that the declaration part is ignored.
PS: Add a piece of code to express the author's meaning
function foo () {} var foo=3; Console.log (foo); // 3 This code will be parsed as: function foo () {} // var foo;//This statement is ignored by foo=3; Console.log (foo); As I understand it:var foo;foo= function foo () {}foo=3; Console.log (foo);
Following the original text, here are some special cases:
1. The built-in variable "arguments" behaves strangely, as if it were defined between a function parameter and a function declaration. This means that if there is a variable in the parameter "arguments", then it will have a higher priority than the built-in "arguments", even if it is undefined. This is not a good feature, do not use "arguments" as the shape parametric name. 2, using "This" as an identifier can cause a syntax error, which is a good feature. 3. If the same name appears in multiple parameters, the last one will have the highest priority, even if it is undefined.
function expression with a name
You can also give a name to a function in a function expression, using a syntax similar to a function declaration. But this does not make it a function declaration, and the function name will not be added to the scope, the function body will not be advanced to the top, the following code to illustrate what I mean:
1Foo ();//TypeError "Undefined is not a function"2Bar ();//valid3Baz ();//TypeError "Undefined is not a function"4Spam ();//referenceerror "spam is not defined"5 6 varfoo=function(){};//anonymous function expression (' foo ' get hoisted)7 functionBar () {};//function declaration (' Bar ' and the function body get hoisted)8 varbaz=functionSpam () {};//named function expression (' only ' baz ' get hoisted)9 TenFoo ();//valid OneBar ();//valid ABaz ();//valid -Spam ();//referenceerror "spam is not defined"
How to use this knowledge to program
Now that you understand the scope and declaration advance features, what are the implications for JavaScript programming? The most important thing is to use the "var" keyword when declaring variables, and I strongly recommend that you write only one var statement at the top of each scope (multivariate, comma-concatenated). If you force yourself to do this, you will not be confused about claims Ascension. However, doing so will make it more difficult to find the declared variables in the current scope, and I recommend using the "onevar" option of "JSLint" to validate the code, and if you do, your code will look like this:
1 /* jslint onevar:true [...] */ 2 function foo (a,b,c) {3 var x=1,4 Bar,5 baz= "Something"; 6 }
See what the specs say.
I find that frequently reviewing the ECMAScript specification documentation helps to directly understand how these mechanisms work, and the following is a description of the specification for variable declarations and scopes:
1 If a variable declaration statement is inside a function declaration, then the variable is defined within the scope of the function (refer to Chapter 10.1.3), otherwise they are defined in the global scope (as a member variable of the global object, refer to Chapter 10.1.3). When a variable enters the scope, it is created, and the block statement does not define a new execution scope, and only the program and function declarations produce a new scope. The variable is initialized to "undefined" when it is created, and a variable with an initialization statement is assigned the value of its assignment expression when the assignment statement executes, not when the variable is created.
I hope this article will help JavaScript developers sort out some confusing questions, and I've made it as clear as possible, so as not to cause more confusion. If you find me wrong or missing something important, be sure to let me know.
= = = after translation = = =
Translation reference: http://ju.outofmemory.cn/entry/85659
Here is an example:
1 varX=0;2 varf=function(){3X=1;4 }5 f ();6 Console.log (x);7 functionf () {8x=2;9 }Ten f (); OneConsole.log (x);
Scopes and declarations in "translation" JavaScript are in advance