let and const commands (test questions)

1. CONST

let user = {name:'Lucy',age:17};
const USER_INFO = user;
console.log(user)
console.log(USER_INFO)
user.age = 32;
console.log(user)
console.log(USER_INFO)


结果:

{name:‘Lucy’,age:17}
{name:‘Lucy’,age:17}
{name:‘Lucy’,age:32}
{name:‘Lucy’,age:32}

2. Undeclared variables will be automatically declared as global variables

let a = 'aaa';
alert(window.a);  
var b = 'bbb';
alert(window.b);  
c = 'ccc'
alert(window.c);  


结果:
undefined
bbb
ccc


3. Scope

if(1){
   var a = 1;
   console.log(a)
}
console.log(a)



结果:
1
1

if(1){
  let a = 1;
  console.log(a)
}
console.log(a)



结果:
1
a is not defined

for (var i = 0; i < 3; i++) {
   console.log(i)
}
console.log(i)



结果:
0 1 2
3

for (let i = 0; i < 3; i++) {
   console.log(i)
}
console.log(i)



结果:
0 1 2
i is not defined

for (let i = 0; i < 3; i++) {
  let i = 'aaa';
  console.log(i);
}



结果:
aaa
aaa
aaa

解析:
for循环设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

for (var i = 0; i < 3; i++) {
    var i = 'bbb';
    console.log(i);
}




结果:
bbb

解析:
两个var声明的 i,都指向一个全局的变量 i 。

for (var i = 0; i < 3; i++) {
    let i = 'bbb';
    console.log(i);
}



结果:
bbb
bbb
bbb

for (let i = 0; i < 3; i++) {
    var i = 'aaa';
    console.log(i);
}



结果:
Identifier ‘i’ has already been declared.(已声明标识符“i”)

var a = [];
for (let i = 0; i < 10; i++) {
    console.log(i);
    a[i] = function () {
        console.log(i);//执行此代码时,for循环已经执行完毕。
    };
}
a[6]();




结果:
0 1 2 3 4 5 6 7 8 9
6

var a = [];
for ( var i = 0; i < 10; i++) {
 console.log(i);
 a[i] = function () {
   console.log(i);  //执行此代码时,for循环已经执行完毕,i 的值是10。
 };
}
a[6]();



结果:
0 1 2 3 4 5 6 7 8 9
10

4. Variable improvement

console.log(a)
var a = 1;



结果:
UNDEFINED

var a = 1;
function foo(){
   if(false){
       var a = 2;
   }
   console.log(a)
}
foo();



结果:
undefined

console.log(a)
let a = 1;



结果:
Cannot access ‘a’ before initialization

解析:
let命令不存在变量提升,所以声明前调用变量,都会报错,这就涉及到一个概念——暂时性死区。

ES6规定,如果区块中存在LET和CONST命令,这个区块对LET和CONST命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。这在语法上,称为“暂时性死区”(TEMPORAL TEAD ZONE,简称TDZ)。

5. Temporary dead zone

var a = 123;
if (true) {
	// 这里会产生 TDZ for a
   a = 'abc';
   let a;//if区块内, 在let命令声明变量a之前,都属于变量a的“死区”。这里结束 TDZ for a
}



结果:
Cannot access ‘a’ before initialization(初始化前无法访问“a”)

解析:
总之,变量一定要在声明之后使用!!!!!

6. Combine SETTIMEOUT and closure

When calling SETTIMEOUT, put the function parameters into the event queue, and wait until the main program finishes running before calling it. Even if the time value is 0, it will wait for the main program to finish executing before executing it. If the main program queue is empty, it will be called directly.

Closure: When passing a value of a function type, it retains a reference to the scope in which it is declared.

for(var i = 0;i < 10; i++){
  console.log(i);
  setTimeout(function () {//同步注册回调函数到异步的宏任务队列
    console.log(i);//执行此代码时,for循环已经执行完毕。
  },0);
}



结果:
0 1 2 3 4 5 6 7 8 9
10 10 10 10 10 10 10 10 10 10

解析:
注意setTimeout函数里面有个匿名函数哦,在执行这个匿名函数中的console.log(i)的时候,因为闭包(保留了对声明i的作用域的引用),var作用域是全局的,现在for执行完了,i的值是10

for(let i = 0;i < 10; i++){
  console.log(i);
  setTimeout(function () {//同步注册回调函数到异步的宏任务队列
    console.log(i);//执行此代码时,for循环已经执行完毕。
  },0);
}



结果:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9

function foo(){
  for(var i = 0;i < 10; i++){
    console.log(i);  
    setTimeout(function (i) { 
      console.log(i);
    },1000);
  }
  for(var i = 0;i < 3; i++){
    setTimeout(function (i) { 
      console.log(i);
    },1000);
    console.log(i);
  }
}
foo()


结果:
0 1 2 3 4 5 6 7 8 9
0 1 2
3 3 3 3 3 3 3 3 3 3
3 3 3

解析:
setTimeout的意思是传递一个函数,延迟一段时间把该函数添加到队列中,并不是立即执行。
如下图所说,异步任务会把回调函数加到任务队列,等主进程的空闲了,才被读取到主进程中执行。
也就是说所有传递给setTimeout的回调方法都会在整个环境下的所有代码运行完毕之后执行。(这就是为什么先输出for里面的,再输出setTimeout函数里面的)
又如下图所说,任务队列是先进先出的,所以先输出10个3,再输出3个3

Guess you like

Origin blog.csdn.net/ljy_1024/article/details/121426772