Easy understanding of Javascript variable-related issues and javascript-related issues

Source: Internet
Author: User

Easy understanding of Javascript variable-related issues and javascript-related issues


Before going back to the content of this article, we will go back to 1995. When Brendan Eich was designing the first version of JavaScript, he made a lot of mistakes. Of course, this also includes a part of the language itself, for example, the Date object, the object multiplication is automatically converted to NaN, and so on. However, looking back, the most important part of the language is the rational design of objects, prototypes, first-class functions with lexical scopes, and variability by default. The language skeleton is very good, and even surpasses people's initial impressions on it.

After that, it was the original design error of Brendan that gave birth to this article. Our goal is very small. You may not notice this problem after using this language for many years, but it is so important, because we may mistakenly assume that this error is the "the good parts" in the language design. (For more information, see Appendix A: Scope description in cancer in the JavaScript language essence ).

Today, we must take down these variables-related issues.

Question #1: JS does not have block-level scope

See this rule:In the var declaration of JS functions, its scope is all of the function bodies.. There is no problem at first glance, but if you encounter the following two situations, you will not get satisfactory results.

First, the scope of a variable declared in a code block is the entire function scope rather than the block-level scope.

You may not have noticed this before, but I am worried that you cannot easily ignore this issue. Let's reproduce the bug caused by this problem.

Assume that your current Code uses a variable t:

Function runTowerExperiment (tower, startTime) {var t = startTime; tower. on ("tick", function (){... code using variable t ...});... more code ...}

So far, everything has been going smoothly. Now you want to add the bowling speed measurement function, so you have added a simple if statement in the callback function.

Function runTowerExperiment (tower, startTime) {var t = startTime; tower. on ("tick", function (){... code using variable t... if (bowlingBall. altitude () <= 0) {var t = readTachymeter ();...}});... more code ...}

Oh, dear, the previous Code "using variable t" runs well. Now you accidentally added the second variable t, t points to a new internal variable t instead of the original external variable.

The scope declared by var in JavaScript is like the paint bucket tool in Photoshop. It spreads forward and backward from the declaration until the boundary of the function is reached. You think, this variable t has a wide scope, so it will be created immediately upon entry into the function. This is the so-called hoisting ). Variable upgrading is like raising the JS engine to the highest position in the function with a very small code Crane.

Now it seems that the improvement feature has its own advantages. If there is no improvement action, many perfect technologies that seem reasonable within the scope of the global scope will become ineffective in calling function expressions (IIFE) immediately. However, in the above case, the upgrade will lead to an unpleasant bug: all the final results of the calculation using the variable t are NaN. This problem is extremely difficult to locate, especially when your code volume is far greater than the previous example of this toy, you will go crazy.

Adding a new code block before the original code block will lead to a strange error. At this time, I will think, who is the problem, my or the system? We don't want to mess up the system ourselves.

However, this problem is much inferior to the next one.

Question #2: excessive variable sharing in a loop

You can guess what happens When you execute the following code, which is very simple:

Var messages = ["Hi! "," I am a web page! "," The alert () method is very interesting! "]; For (var I = 0; I <messages. length; I ++) {alert (messages [I]);}

If you keep following the articles in this column, you know that I like to usealert()Method. Maybe you knowalert()It is not a good API, It is a synchronous method, so when a warning dialog box pops up, the input event will not be triggered, your JS Code, including your entire UI, it is paused until you click OK.

Do not use it easilyalert()To implement functions in Web pages. The reason why I use them in code is thatalert()Features make it a very useful tool for teaching.

Besides, if you give up all the heavy methods and bad behaviors, you can make a talking cat. Why not?

Var messages = ["Meow! "," I am a talking cat! "," Callback is very interesting! "]; For (var I = 0; I <messages. length; I ++) {setTimeout (function () {cat. say (messages [I]) ;}, I * 1500 );}

However, there must be something wrong. The talking cat didn't even say three messages as expected. It said three times "undefined ".

Do you know where the problem is?

Can you see the caterpillar on the tree (bug? (Image Source: nedevil saveri)

In fact, the answer to this question is that the Loop itself and the three timeout callbacks share the unique variable I. When the loop ends, the value of I is 3 (becausemessages.lengthThe value is 3). At this time, the callback has not been triggered.

So when the first timeout is executedcat.say(messages[i]) At this time, the I value is 3, so the cat finally prints the value of messages [3], that is, undefined.

There are many ways to solve this problem (there is one here), but you think it will be troublesome for you to use the var scope rules one after another. If you can completely solve this problem in the first place, how nice it is!

Let is a more perfect var

Most JavaScript design errors (other languages are also available, but JavaScript is too prominent) cannot be fixed. Maintaining backward compatibility means that JavaScript code behavior on the Web Platform will never be changed, even if the standard committee does not have the right to require fixing the weird feature of automatic insertion of semicolons in JavaScript; browser vendors will never make any breakthrough changes, because it hurts their loyal users.

So about a decade ago, Brendan Eich decided to fix the problem, but there was only one solution.

He added a new Keyword: let. Like var, let can also be used to declare variables, but it has better scope rules.

It looks like this:

let t = readTachymeter();


for (let i = 0; i < messages.length; i++) { ... }

Let and var are different, so if you just replace var global search with let in the Code, some unique features that depend on var Declaration (You may not intentionally write it like this) the Code may not run properly. But for the vast majority of code, in the new code mode of ES6, you should stop using var to declare variables and use let! From now on, remember this phrase: "let is a more perfect var ".

So what is the difference between let and var? I'm very glad you raised this question!

This rule helps you capture bugs. In addition to the NaN error, every exception will be thrown in the current row.

The variables declared by let have block-level scopes. That is to say, the scope of the variables declared with let is only the outer block, not the entire outer function.

The let statement retains the upgraded features, but does not blindly improve. In the runTowerExperiment example, you can quickly fix the problem by replacing var WITH let. If you use let everywhere for declaration, you will not encounter similar bugs.

The global variables declared by let are not attributes of the global object. This means that you cannot access these variables through window. Variable names. They only exist in the scope of an invisible block. This block is theoretically an external block of all JS Code running on the Web page.

Shapefor (let x...)Each iteration creates a new binding for x.

This is a very subtle difference. Let's look at the example of a talking cat.for (let...)If the loop is executed multiple times and the loop maintains a closure, each closure captures different values of a loop variable as a copy, instead of capturing the same value of the loop variable for all closures.

So in the talking cat Example, you can also replace var WITH let to fix the bug.

This situation applies to three existing loop methods: for-of, for-in, and the traditional Class C loop separated by semicolons.

The variables declared by let are loaded only when the control flow reaches the Code defined for the variable. Therefore, using this variable before arrival triggers an error. For example:

Function update () {console. log ("current time:", t); // reference error (ReferenceError)... let t = readTachymeter ()}

During this period of time that cannot be accessed, the variables remain in the scope, but are not yet loaded. They are located in the temporary Dead Zone (Temporal Dead Zone, TDZ for short. I have always wanted to use sci-fi novels to draw a line from this brain hole, but I haven't thought about it yet.

(Fragile performance details: In most cases, you can check the code to identify whether the declaration has been executed. Therefore, in fact, the JavaScript engine does not need to execute an additional variable access check every time the Code is run to ensure that the variable has been initialized. However, the closure is sometimes not transparent, and the JavaScript engine will perform a runtime check, which means that let is relatively slow compared with var .)

(Details of the fragile parallel universe scope: In some programming languages, the scope of a variable begins with declaration, rather than covering the entire closed block. The Standards Committee has considered granting this scope criterion to the let keyword. However, once this criterion is used, statements that use variables in advance may cause a reference error (ReferenceError ), currently, this statement is not in the Declaration scope of let t, and does not reference the variable t here. Instead, it references the corresponding variable in the outer scope. However, this method cannot be well combined with the improvement of closures and functions, so the proposal was rejected .)

When you use let to redefine a variable, a syntax error (SyntaxError) is thrown ).

This rule can also help you detect trivial issues. Indeed, this is also the difference between var AND let. When you replace the global search var WITH let, The let redefinition syntax is also incorrect, because this rule is also effective for global let variables.

If the same global variables are declared in multiple scripts, you 'd better continue to declare these variables with var. If you replace let, all the loaded scripts fail to be executed and an error is thrown.

Or you can consider using the ES6 built-in module mechanism, which will be explained in detail in the following article.

(Fragile syntax details: let is a reserved word in a strict mode. In non-strict mode, for backward compatibility purposes, you can still declare variables, functions, and parameters using the let name. Although you will not be stupid, but you can write code like var let = 'q! But let; in any case, it is invalid .)

Apart from those differences, let and var are almost similar. For example, they all support the use of commas to separate multiple variables, and both support the deconstruct feature.

Note:, The class declaration behavior is different from var and consistent with let. If you load a script containing a class with the same name, a redefinition error will be thrown for the class defined later.


Yes, there is a new keyword!

The third declarative keyword introduced by ES6 is similar to let: const.

The variables declared by const are similar to those declared by let. The difference is that the variables declared by const can only be assigned values during declaration and cannot be modified at will, otherwise, SyntaxError occurs ).

Const MAX_CAT_SIZE_KG = 3000; // The correct MAX_CAT_SIZE_KG = 5000; // syntax error (SyntaxError) MAX_CAT_SIZE_KG ++; // The syntax error is still caused by a syntax error even though the syntax is changed.

Of course, it is wise to design a specification. A value must be assigned after the variable is declared with const. Otherwise, a syntax error is thrown.

Const theFairest; // still a syntax error.

Mysterious proxy namespace

"Namespace is a wonderful idea. We should make more use of it !" -- Tim Peters: "This is the Zen of Python"

Nested scopes are one of the core concepts behind programming languages. This concept was started with ALGOL about 57 years ago. Now, looking back, we can see that the decision was extremely correct.

Before ES3, JavaScript only has the global scope and function scope. (Let's ignore the with statement .) ES3 introduces a try-catch statement, which means that a new scope is generated in the language and is only used for exception variables in the catch Block. ES5 adds a scope for strict eval () methods. ES6 adds block scope, for loop scope, new global let scope, module scope, and the additional scope used to evaluate the default value of parameters.

All other scopes added since ES3 are very important. Their addition makes JavaScript object-oriented features run as smoothly and accurately as closures, of course, closures can also seamlessly link these scopes to implement various functions. Maybe you have never noticed the existence of these scope rules before reading this article. If this is the case, then the language completes its job properly.

Can I use let and const now?

Yes. To use the let and const features on the Web, you need an ES6 interpreter such as Babel, Traceur, or TypeScript. (Currently, Babel and Traceur do not support the temporary dead zone feature .)

Io. js supports let and const, but can be used only in strict mode. Node. js is also supported, but the -- harmony option must be enabled.

Nine years ago, Brendan Eich implemented the first version of let keywords in Firefox. This feature was thoroughly redesigned in subsequent standardization processes. Shu-yu Guo is upgrading the original implementation according to the new standard. This project was reviewed by Jeff Walden and others.


The above is all about this article. I hope this article will help you in your study or work. If you have any questions, please leave a message.

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.