本篇文章的重点是学习如何使用 JavaScript 新的语法 let 声明变量以及作用域的理解。
1、let 基本介绍
JavaScript ES6 引入了 let ,用 let 声明变量,解决了 JavaScript 没有块级作用域的问题(注意:ES3 的 catch 分句会产生块作用域)
对于新手而言,ES6 之前,JavaScript 没有块级作用域,使用 var 声明变量,会让 JavaScript 不易懂和难以调试,用不好甚至有内存泄露的可能。至于为什么会这样,主要是没有清楚作用域的概念,下面首先了解一下什么是作用域。
2、作用域介绍
1)作用域
作用域简单的来说,就是一套寻找变量的规则,用于确定在何处以及如何查找变量。 在 ES6 代码之前,只有全局作用域和函数作用域。
当一个块或函数嵌套在另一个函数时,就发生了作用域嵌套,如下所示,就有三个嵌套作用域:
function foo(a) {
var b = a * 2;
function bar(c) {
console.log (a, b, c) ;
}
bar (b * 3);
}
foo ( 2 ) ; // 2, 4 , 12
// 1、全局作用域,其中有一个标识符:foo;
// 2、 foo 创建的函数作用域,其中有三个标识符:a ,bar 和 b
// 3、bar 创建的函数作用域,其中有一个标识符:c
如何在嵌套作用域中寻找变量?
引擎从当前作用域开始查找变量,如果找不到,就会向上一级继续查找。当抵达最外层全局作用域时,无论找到还是没有找到,查找过程中都会停止。
2)全局作用域和函数作用域
使用 var 声明变量时,如果在函数外声明,就是全局变量,任何函数都可以进行使用,这就是全局作用域查找。
如果在函数内使用 var 声明变量,就是函数作用域查找,只能在函数内部进行访问,外部不能进行访问:
var a = 12; //全局作用域都能进行访问
function myFunction () {
alert ( a ); // 12
var b = 13 ;
if ( true ) {
var c = 14 ; // 函数内部可以访问
alert ( b ) ; //13
}
alert ( c ) ; //14
}
myFunction ();
alert ( b ) ; //undefined
3)块级作用域
在 ES6 中引入了 let ,避免了有 var 声明变量的一些问题,让变量和函数不仅可以属于所处的作用域,也可以属于某个代码块 (通常是 { ... } 内部) , 另外,在块级作用域定义的变量,块级作用域外是无法访问的。
let a = 12 ; //全局作用域 , 可以访问
function myFunction () {
console.log ( a ) ; // 12
let b = 13;
if ( true ) {
let c = 14;
alert ( b ); //13
}
alert ( c ) ; //undefined {}外,因此无法访问
}
myFunction ();
alert( b ) ; // undefined { } 外,因此无法访问
3、var 和 let 的区别
1) let 和 const 不存在变量提升机制
创建变量的六种方式中:var / function 有变量提升, 而 let / const / class / import 都不存在这个机制
2)var 允许重复声明,而 let 不允许重复声明
在相同的作用域 ( 或执行上下文中)
—— 如果使用 var / function 关键字声明变量并且重复声明, 是不会有影响的 (声明第一次之后,之后再遇到就不会再重复声明了)
—— 但使用 let / const 就不行, 浏览器会校验当前作用域中是否已经存在这个变量了,如果存在了,则再次基于 let 等重新声明就会报错
3)let 会产生块级作用域
4、重复定义变量的问题
用 var在同一个作用域重复定义变量,后者将会覆盖前者声明的变量的值,如下:
var a = 0 ;
var a = 1 ;
alert ( a ) ; // 1
function myFunction ( ) {
var b = 2;
var b = 3;
alert ( b ); // 3;
}
myFunction ( );
使用 let 在同一作用域下重复定义变量,将会产生 Syntaxerror 的错误,如下:
let a = 0;
let a = 1; // SyntaxError
function myFunction ( ) {
let b = 2;
let b = 3 ; // SyntaxError
if ( true ) {
let c = 4;
let c = 5 ; // SyntaxError
}
}
myFunction();
如果你在嵌套作用域里进行重新定义变量 , 虽然变量名相同 , 但是不是同一变量,如下:
var a = 1;
var b = 2;
function myFunction ( ) {
var a = 3; // different variable
let b = 4 ; //different variable
if ( true ) {
var a = 5 ; // overwritten
let b = 6 ; //different variable
console.log (a ); //5
console.log ( b ); //6
}
console.log ( a ) ; //5
console.log ( b ) ; // 4
}
myFunction ( );
console.log ( a );
console.log( b );
5、提升概念的问题
直觉上会认为编译器会由上到下一行行的执行,起始并不正确,函数声明和变量声明都会被提升 ( 使用 var 声明变量 , let 声明变量将不会被提升 )。函数首先会被提升 , 然后才是变量提升。