本篇文章的重點(diǎn)是學(xué)習(xí)如何使用 JavaScript 新的語(yǔ)法 let 聲明變量以及作用域的理解。
1、let 基本介紹
? ? JavaScript ES6 引入了 let ,用 let 聲明變量,解決了 JavaScript 沒(méi)有塊級(jí)作用域的問(wèn)題(注意:ES3 的 catch 分句會(huì)產(chǎn)生塊作用域)
? ? 對(duì)于新手而言,ES6 之前,JavaScript 沒(méi)有塊級(jí)作用域,使用 var 聲明變量,會(huì)讓 JavaScript 不易懂和難以調(diào)試,用不好甚至有內(nèi)存泄露的可能。至于為什么會(huì)這樣,主要是沒(méi)有清楚作用域的概念,下面首先了解一下什么是作用域。
2、作用域介紹
? ? 1)作用域
? ? ? ? 作用域簡(jiǎn)單的來(lái)說(shuō),就是一套尋找變量的規(guī)則,用于確定在何處以及如何查找變量。 在 ES6 代碼之前,只有全局作用域和函數(shù)作用域。
? ? 當(dāng)一個(gè)塊或函數(shù)嵌套在另一個(gè)函數(shù)時(shí),就發(fā)生了作用域嵌套,如下所示,就有三個(gè)嵌套作用域:
? ?function foo(a) {
? ? ? ? ? ? var b = a * 2;
? ? ? ? ? ? function bar(c) {
? ? ? ? ? ? ? ? ? ? console.log (a, b, c) ;
? ? ? ? ? ? }
? ? ? ? ? ? bar (b * 3);
? ? }
? ? foo ( 2 ) ; // 2, 4 , 12
// 1、全局作用域,其中有一個(gè)標(biāo)識(shí)符:foo;
// 2、? foo 創(chuàng)建的函數(shù)作用域,其中有三個(gè)標(biāo)識(shí)符:a ,bar 和 b
// 3、bar 創(chuàng)建的函數(shù)作用域,其中有一個(gè)標(biāo)識(shí)符:c?
? ?如何在嵌套作用域中尋找變量?
? ? 引擎從當(dāng)前作用域開(kāi)始查找變量,如果找不到,就會(huì)向上一級(jí)繼續(xù)查找。當(dāng)?shù)诌_(dá)最外層全局作用域時(shí),無(wú)論找到還是沒(méi)有找到,查找過(guò)程中都會(huì)停止。
2)全局作用域和函數(shù)作用域
? ? 使用 var 聲明變量時(shí),如果在函數(shù)外聲明,就是全局變量,任何函數(shù)都可以進(jìn)行使用,這就是全局作用域查找。
? ? 如果在函數(shù)內(nèi)使用 var 聲明變量,就是函數(shù)作用域查找,只能在函數(shù)內(nèi)部進(jìn)行訪問(wèn),外部不能進(jìn)行訪問(wèn):
????var a = 12; //全局作用域都能進(jìn)行訪問(wèn)
????function myFunction () {
? ? ? ? alert ( a );? // 12
? ? ? ? var b = 13 ;?????
? ? ? ? if ( true ) {
? ? ? ? ? ? var c = 14 ; // 函數(shù)內(nèi)部可以訪問(wèn)
? ? ? ? alert ( b ) ; //13
? ? ? ? }
? ? ? ? alert ( c ) ;? //14
? ? }
? ? myFunction ();
? ? alert ( b ) ;? //undefined
? ? 3)塊級(jí)作用域
在 ES6 中引入了 let ,避免了有 var 聲明變量的一些問(wèn)題,讓變量和函數(shù)不僅可以屬于所處的作用域,也可以屬于某個(gè)代碼塊 (通常是 { ... } 內(nèi)部) , 另外,在塊級(jí)作用域定義的變量,塊級(jí)作用域外是無(wú)法訪問(wèn)的。
?let a = 12 ; //全局作用域 , 可以訪問(wèn)
? function myFunction () {
? ? ? ? console.log ( a ) ; // 12
? ? ? ? let b = 13;
? ? ? ? if ( true ) {
? ? ? ? ? ? let c = 14;
? ? ? ? ? ? alert ( b );? //13
? ? ????}
? ? ? ? alert ( c ) ; //undefined {}外,因此無(wú)法訪問(wèn)
? ? }
myFunction ();
alert( b ) ; // undefined { } 外,因此無(wú)法訪問(wèn)
3、var 和 let 的區(qū)別
1) let 和 const 不存在變量提升機(jī)制
? ? 創(chuàng)建變量的六種方式中:var / function 有變量提升, 而 let / const / class / import 都不存在這個(gè)機(jī)制
2)var 允許重復(fù)聲明,而 let 不允許重復(fù)聲明
? ? 在相同的作用域 ( 或執(zhí)行上下文中)
? ? —— 如果使用 var / function 關(guān)鍵字聲明變量并且重復(fù)聲明, 是不會(huì)有影響的 (聲明第一次之后,之后再遇到就不會(huì)再重復(fù)聲明了)
? ? —— 但使用 let / const 就不行, 瀏覽器會(huì)校驗(yàn)當(dāng)前作用域中是否已經(jīng)存在這個(gè)變量了,如果存在了,則再次基于 let 等重新聲明就會(huì)報(bào)錯(cuò)
3)let 會(huì)產(chǎn)生塊級(jí)作用域
4、重復(fù)定義變量的問(wèn)題
用 var在同一個(gè)作用域重復(fù)定義變量,后者將會(huì)覆蓋前者聲明的變量的值,如下:
var a = 0 ;?
var a = 1 ;
alert ( a ) ; // 1
function myFunction ( ) {
? ? ? ? var b = 2;?
? ? ? ? var b = 3;
? ? ? ? alert ( b ); // 3;
? ? }
? ? myFunction ( );
使用 let 在同一作用域下重復(fù)定義變量,將會(huì)產(chǎn)生 Syntaxerror 的錯(cuò)誤,如下:
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();
如果你在嵌套作用域里進(jìn)行重新定義變量 , 雖然變量名相同 , 但是不是同一變量,如下:
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、提升概念的問(wèn)題
直覺(jué)上會(huì)認(rèn)為編譯器會(huì)由上到下一行行的執(zhí)行,起始并不正確,函數(shù)聲明和變量聲明都會(huì)被提升 ( 使用 var 聲明變量 , let 聲明變量將不會(huì)被提升 )。函數(shù)首先會(huì)被提升 , 然后才是變量提升。