Why JavaScript doesn't have block-level scopes _javascript tips

Source: Internet
Author: User

Recently in the ES2015 combat, there is a sentence to say so

There is no block level scope in JavaScript

May be a little confused about this issue, let's look at an example

var a = [] for
(var i = 0; i < i++) {
 A[i] = function () {
 console.log (i);
 }
}
A[6] ();

I think a lot of people will think the result of this problem is 6, but unfortunately the answer is 10. Try something else. A[7] (), a[8] (), a[8] () The results are 10!!
Because JS in processing primitive variables, many times the primitive variable will be packaged into the corresponding object to deal with, such as for var str = "Hello World"; Str.slice (1).
The real process of JS is probably var str = "Hello world"; new String (str). Slice (1). Such a process may be a problem for us to understand.
In order to explain this problem and I belong to the number type in the primitive type, I explicitly declare the number type. Because the basic type of the assignment process is to reapply the memory, modify the direction of the variable's process, we also use new to this process The process of the number object to simulate. The modified code is as follows:

var a = []
var i = new number (0);
for (; i < i = new number (i+1)) {
 A[i] = function () {
 console.log (i.tostring ());
 }
A[6] ();
A[7] () ()//
a[8] ();//
a[9] ();//10

Let's take a look at the relative memory address of these variables in the following procedure.

(function () {
  var id = 0;

  function Generateid () {return id++;};

  Object.prototype.id = function () {
    var newId = Generateid ();

    This.id = function () {return newId;};

    return NewId
  };}
) ();

var a = []
var i = new number (0);
Console.log (I.id ());//0
for (; i < i = new number (i+1), i.id ()) {

 A[i] = function () {
 Console.log ( I.id ());
 Console.log (i.ToString ());
 }
A[6] (); Ten
A[7] ()///
A[8] ()///
a[9] ()//
Console.log (I.id ())//10

The effect of the whole "assignment" of our I in this side is actually simulated, and the relative address of I is changed from 0 to 10 (finally it needs to be added once to jump out of the For loop).
While looking at the relative address of I, we found a problem: a[x] (x:0~9) The corresponding function at the time of execution, the reference to the relative address of I is 10. Why?
This is going to involve a block-level scoping problem, and here we quote Nanyi's passage in ES6:

ES5 only global scope and function scopes, no block-level scopes.

ES5 is the most widely used version of JS. In JavaScript, there is no block scope. There are only global scope and block-level scopes.
How do you understand that? For instance,

for (var i = 0;i < i++) {
 console.log (i);
}
Console.log (i);//10
Console.log (window.i);//10

Intuitively, we think the For loop is a code block that should belong to a block-level scope. But not only does the normal output 0~9, but it can also output 10 out of the for loop. And we find that although we are defined on the For loop I, But it seems I was hanging on the global window object (if it's a Nodejs execution environment, it hangs on the global object)

So blocks like the For loop in JavaScript don't play a block-level effect, and defining variables in a code block such as a For loop is no different than defining a variable directly in the current scope.

But we can isolate the scope by function:

(function () {for
 (var i = 0;i < i++) {
 console.log (i);
 }
 Console.log (i);
}) ()
console.log (i);////i is not defined
 

At the same time, if the Console.log (WINDOW.I) is executed, the result of undefined will be obtained. Here we use an immediate execution function to form a scope. Acts like a block of code, out of the scope of this function, I can no longer access the variable i. However, I can be accessed arbitrarily within a function scope.
Back to the previous question, combine JavaScript with only global scope and block-level scopes to understand. We in the For loop, the definition of I is definitely defined in the current scope, that is, the window scope. In the loop body, we assign a function to A[i. When we execute this function, the situation is as follows:

I is not present in the function, then the scope chain goes to the window scope to find the I. The I that we output this time is this I. Since I was +1 of the last time I jumped out of the loop, I turned 10, so the output was always 10. But the I that we really need is not the last I, But in the middle of the process I. If we want to solve this problem, we need to throw away the variable of I (because the last I inevitably becomes 10). We want to have the function of a[0] reference the value of 0, so that the function of a[1] refers to the value 1. The following figure shows:

In the code before returning to us.

Our arrows in the diagram are out of the right access I (0~9). This is because the For loop does not form a block-level scope itself. This leads us to access the For loop definition of I as we go along the scope chain to access I.
Here we use an immediate execution function to wrap our code, we can form a scope, and at the same time we pass a value for it as follows:

var a = []
var i = new number (0);
Console.log (I.id ());//0
for (; i < i = new number (i+1), i.id ()) {

 (function (i) {
 A[i] = function () {
  Console.log (I.id ());
  Console.log (i.ToString ());
 }
 ) (i);
A[6] (); 6 6
A[7] ()//7 7
A[8] ()//8 8
a[9] ();//9 9
Console.log (I.id ());


Because this immediate execution function refers to the numeric 0~9, when we perform the function a[i], we find the scope of the immediate execution function along the scope chain. Immediately executes the function to maintain the 0~9 numeric reference, and we can correctly output the value of I in the function a[i]. By executing the result, we can see , not only is the execution result correct, but the relative memory address of the value we are referencing is also correct. Then we change the number object that was originally used to test the explicit declaration. as follows:

var a = [];
for (var i = 0; i < i++) {
 (function (i) {
 A[i] = function () {
  console.log (i);
 }
 }) (i);
}

Finally, let's look at how ES6 's syntax suggests using let instead of Var and the code that generates ES5 by Bable compilation:

ES6 code
var a = [] for
(Let i = 0; i < i++) {
 A[i] = function () {
 console.log (i);
 }
}
A[6] ();
Babel compiles the generated ES5 code
"use strict";
var a = [];
var _loop = function _loop (i) {
 A[i] = function () {
 console.log (i);
 };
}
; for (var i = 0; i < i++) {
 _loop (i);
}
A[6] ();



Look ~ Our solutions and ES6 solutions are very similar. Here our immediate execution function corresponds to the _loop function in the generated ES5 code and the execution of _loop (i).

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.