Home  >  Article  >  Web Front-end  >  In-depth understanding of Javascript scope and variable promotion_javascript skills

In-depth understanding of Javascript scope and variable promotion_javascript skills

WBOY
WBOYOriginal
2016-05-16 17:10:181057browse

What is the result of the following program?

Copy code The code is as follows:

var foo = 1;
function bar() {
if (!foo) {
var foo = 10;
}
alert(foo);
}
bar();

The result is 10;

What about the following one?

Copy code The code is as follows:

var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);

The result is 1.

Shocking you? What happened? This may be strange, dangerous, and confusing, but it is also actually a very useful and impressive JavaScript language feature. I don't know if there is a standard name for this behavior, but I like this term: "Hoisting". This article will give an introductory explanation of this mechanism, but first let us have some necessary understanding of the scope of JavaScript.

Scope of Javascript

For Javascript beginners, one of the most confusing points is scope; in fact, it’s not just beginners. I have met some experienced JavaScript programmers, but they do not understand scope deeply. The reason why JavaScript scope is confusing is because the program syntax itself looks like a C family language, like the following C program:

Copy code The code is as follows:

#include
int main() {
int x = 1;
printf("%d, ", x); // 1
if (1) {
int x = 2;
printf("%d, ", x); // 2
}
printf("% dn", x); // 1
}

The output result is 1 2 1. This is because the C family language has block scope. When program control enters a block, such as If block, variables that only affect the block can be declared without affecting the scope outside the block. But in Javascript, this doesn't work. Take a look at the code below:
Copy the code The code is as follows:

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

The result will be 1 2 2. Because javascript is function scope. This is the biggest difference from the C family of languages. The if in this program does not create a new scope.

For many C, c, java programmers, this is not what they expect and welcome. Fortunately, due to the flexibility of JavaScript functions, there are ways to work around this. If you must create a temporary scope, you can do it like this:

Copy the code The code is as follows:

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

This method is very flexible and can be used anywhere you want to create a temporary scope place. Not just within the block. However, I strongly recommend that you take the time to understand JavaScript scoping. It's very useful and one of my favorite features of JavaScript. If you understand scope, then variable hoisting will make more sense to you.

Variable declaration, naming, and promotion

In JavaScript, there are 4 basic ways for variables to enter scope:

•1 Language built-in: all scopes have this and arguments; (Translator's Note: After testing, arguments are not visible in the global scope)

•2 Formal parameters: The formal parameters of the function will be part of the scope of the function body;

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

•4 Variable declaration: like this: var foo;

Function declarations and variable declarations are always quietly "promoted" to the top of the method body by the interpreter. This means, like the following code:

Copy the code The code is as follows:

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

will actually be interpreted as:
Copy the code The code is as follows:

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

No matter whether the block in which the variable is defined can be executed. The following two functions are actually the same thing:
Copy the code The code is 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;
}

Please note that variable assignments are not hoisted, just declarations. However, the function declaration is a little different, and the function body is also promoted. But please note that there are two ways to declare functions:
Copy the code The code is as follows:

function test() {
foo(); // TypeError "foo is not a function"
bar(); // "this will run!"
var foo = function () { // Variable Pointing to function expression
alert("this won't run!");
}
function bar() { // Function declaration function name is bar
alert("this will run!" );
}
}
test();

In this example, only functional declarations will be promoted together with the function body. The declaration of foo will be hoisted, but the function body it points to will only be assigned during execution.

The above covers some of the basics of boosting, and they don’t seem that confusing. However, in some special scenarios, there is still a certain degree of complexity.

Variable parsing order

The most important thing to keep in mind is the order of variable resolution. Remember the 4 ways that naming enters the scope I gave earlier? The order in which variables are parsed is the order I listed them.

Copy code The code is as follows:

<script><br>function a(){ <br>}<br>var a;<br>alert(a);//Print out the function body of a<br></script>

<script></p> <p>var a;<br>function a(){ <br>}<br>alert(a);//Print out the function body of a<br></script>
//But be careful Distinguish the difference from the following two writing methods:
<script><br>var a=1;<br>function a(){ <br>}<br>alert(a);//print out 1<br></script>

<script><br>function a(){ <br>}</p> <p>var a=1;</p> <p>alert(a);//print out 1<br></script>


There are 3 exceptions here:

1 The built-in name arguments behaves strangely. It seems that it should be declared after the function formal parameters, but before the function declaration. This means that if there are arguments in the formal parameter, it will have priority over the built-in one. This is a very bad feature, so avoid using arguments in formal parameters;

2 Defining this variable anywhere will cause a syntax error, which is a good feature;

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

Named function

You can give a function a name. If so, it is not a function declaration, and the specified function name (if any, such as spam below, translator's note) in the function body definition will not be promoted, but ignored. Here is some code to help you understand:

Copy the code The code is 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 points to an anonymous function
function bar() {}; // Function declaration
var baz = function spam() {}; // Named function, Only baz is promoted, spam will not be promoted.

foo(); // valid
bar(); // valid
baz(); // valid
spam(); // ReferenceError "spam is not defined"


How to write code

Now that you understand scoping and variable hoisting, what does this mean for JavaScript coding? The most important thing is to always define your variables with var. And I strongly recommend that for a name, there should always be only one var declaration in a scope. If you do this, you won't have scope and variable hoisting issues.

How to say language specification

I always find the ECMAScript reference documentation helpful. Here's what I found about scoping and variable hoisting:

If a variable is declared in a function body class, it is function scope. Otherwise, it is globally scoped (as a property of global). Variables will be created when execution enters scope. Blocks will not define new scopes, only function declarations and procedures (the translator thinks it is global code execution) will create new scopes. Variables are initialized to undefined when they are created. If there is an assignment operation in the variable declaration statement, the assignment operation will only occur when it is executed, not when it is created.

I hope this article will bring a ray of light to programmers who are confused about JavaScript. I also try my best to avoid causing more confusion. If I said something wrong or overlooked something, please let me know.

Translator’s supplement

A friend reminded me that I discovered the problem of improving named functions in the global scope under IE:

This is what I tested when I translated the article:

Copy the code The code is as follows:

<script><br>functiont(){<br>spam();<br>var baz = function spam() {alert('this is spam')};<br>}<br>t() ;<br></script>

This way of writing, that is, the promotion of named functions in non-global scope, has the same performance under IE and FF. I changed it to:
Copy code The code is as follows:

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

Then spam can be executed under ie, but not under ff. Explanation Different browsers handle this detail differently.

This question also led me to think about two other questions, 1: For variables that act globally on the scope, there is a difference between var and non-var. Without var, the variable will not be promoted. For example, of the following two programs, the second one will report an error:

Copy the code The code is as follows:

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

Copy Code The code is as follows:

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

2: Local variables created in eval will not be promoted (it has no way to do it).
Copy code The code is as follows:

<script><br>var a = 1;<br>function t(){<br> alert(a);<br> eval('var a = 2');<br> alert(a);<br>}<br>t();<br>alert(a);<br></script>
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn