1. 程式人生 > >[js高手之路]var, let, const詳解

[js高手之路]var, let, const詳解

兩種 控制 ghost 花括號 pre 內部 span lec 同名

 1         function show( flag ){
 2             console.log( a );
 3             if( flag ){
 4                 var a = ‘ghostwu‘;
 5                 return a;
 6             } else {
 7                 console.log( a );
 8                 return null;
 9             }
10         }    

我們從es5的變量提升開始說起, 由於變量提升的原因, 上述程序, 在第2行和第7行都能訪問到a的值, 只不過是undefined, 如果你不熟悉javascript這種變量的預解釋機制,可能會認為第2行和第7行會報錯, 只有flag為true的時候,變量a才聲明了, 其實javascript在詞法解釋的時候,會把上述代碼解釋成下面的樣子:

 1        function show( flag ){
 2             var a;
 3             console.log( a );
 4             if( flag ){
 5                 a = ‘ghostwu‘;
 6                 return a;
 7             } else {
 8                 console.log( a );
 9                 return null;
10             }
11         }        

這種機制,在項目中經常誤導程序員,哪怕是資深的前端程序員,不小心也容易入坑, 於是ES6引入了塊級作用域來強化對變量生命周期的控制.

什麽是塊級作用域?

1,函數內部

2,塊中( 通常指的是一對花括號之間)

es6中使用新的關鍵詞 let 來定義變量, 為塊級作用域,上例,如果改成let聲明

 1     function show( flag ){
 2             console.log( a );
 3             if( flag ){
 4                 let a = ‘ghostwu‘;
 5                 return
a; 6 }else { 7 console.log( a ); 8 return nul; 9 } 10 }

由於let是塊級作用域,不會像var一樣 產生變量提升, 所以,第2行和第7行 這個時候報錯( a is not defined )

只有在flag為true的情況,a會被定義, 而且訪問範圍在第3行和第6行的大括號之間, 超出這個範圍,就訪問不到a, 這就是塊級作用域

let都有哪些特性呢?

在同一個作用域下,let不能重復定義兩個同名的標識符

在不同的作用域下,可以使用同名的標識符

1 var a = ‘ghostwu‘;
2 let a = ‘ghostwu2‘;
1 let a = ‘ghostwu‘;
2 let a = ‘ghostwu2‘;

以上兩種方式,都會報重定義錯誤(Identifier ‘a‘ has already been declared)

1         let a = 10;
2         if( a ){
3             let a = 100;
4             console.log( a ); //100
5         }
6         console.log( a ); //10    

以上這種方式,不會報錯,因為是兩個不同的作用域

let的經典應用

在4個按鈕中,獲取當前被點擊按鈕的索引

 1      <script>
 2         window.onload = function(){
 3             var aInput = document.querySelectorAll("input");
 4             for( var i = 0; i < aInput.length; i++ ){
 5                 aInput[i].onclick = function(){
 6                     alert( i );
 7                 }
 8             }
 9         }
10     </script>
11 
12    <input type="button" value="按鈕1">
13     <input type="button" value="按鈕2">
14     <input type="button" value="按鈕3">
15     <input type="button" value="按鈕4">

如果,我們用上面的方法做, 每個按鈕點擊之後 i 都是4, 因為4個按鈕綁定完事件之後,i的值就變成了4, 下次點擊按鈕的時候,所有的都是4, 因為 i = 4 是共享的

通常,我們會在每個按鈕上,加一個自定義索引 綁定 對應的 i 值,再借助this關鍵字,就可以如願以償,如下:

1         window.onload = function(){
2             var aInput = document.querySelectorAll("input");
3             for( var i = 0; i < aInput.length; i++ ){
4                 aInput[i].index = i;
5                 aInput[i].onclick = function(){
6                     alert(this.index);
7                 }
8             }
9         }

還有另一種方法,就是借用立即表達式+閉包的形式, 如下:

 1         window.onload = function(){
 2             var aInput = document.querySelectorAll("input");
 3             for( var i = 0; i < aInput.length; i++ ){
 4                 aInput[i].onclick = (function( j ){
 5                     return function(){
 6                         alert( j );
 7                     }
 8                 })( i );
 9             }
10         }    

而采用let關鍵字, 利用塊級作用域的特性,就可以輕松達到目的

1         window.onload = function(){
2             var aInput = document.querySelectorAll("input");
3             for( let i = 0; i < aInput.length; i++ ){
4                 aInput[i].onclick = function(){
5                     alert( i );
6                 };
7             }
8         }

var在全局作用域下,會把屬性綁定到window上,從而可能產生覆蓋屬性的隱患,而let關鍵字只是會遮蔽它,並不會覆蓋window上的同名屬性

 1         var a = 10;
 2         console.log( a );  //10
 3         console.log( window.a ); //10
 4         console.log( ‘a‘ in window ); //true
 5 
 6         let user = ‘ghostwu‘;
 7         console.log( user ); //ghostwu
 8         console.log( window.user ); //undefined
 9         console.log( ‘b‘ in window  ); //false
10 
11 
12         /*
13         var RegExp = ‘ghostwu‘;
14         console.log( RegExp );  //ghostwu
15         console.log( window.RegExp ); //ghostwu
16         console.log( ‘RegExp‘ in window ); //true
17         */
18 
19         let RegExp = ‘ghostwu‘;
20         console.log( RegExp );  //ghostwu
21         console.log( window.RegExp ); //function RegExp() { [native code] }
22         console.log( ‘RegExp‘ in window ); //true    

const關鍵字是用來定義常量的,它有如下特性:

.塊級作用域

.聲明的時候,必須賦予初始值

.不能被重新賦值

.如果值是一個對象, 那麽對象裏面的屬性是允許被修改的

.不能跟其他標識符重名

1         const user = ‘ghostwu‘;
2         console.log( user );
3         user = ‘zhangsan‘; //報錯, 不能重新賦值
1 const user; //報錯,定義的時候 沒有給初始值
1         const user = {
2             name  : ‘ghostwu‘
3         };
4         console.log( user.name ); //ghostwu
5         user.name = ‘zhangsan‘;  //對象的屬性允許被修改
6         console.log( user.name ); //zhangsan
1        const user = {
2             name  : ‘ghostwu‘
3         };
4         user = {    //報錯,不能重新給user賦值
5             name : ‘zhangsan‘
6         }
7         console.log( user.name ); //報錯
1         var a = 10;
2         const a = 10; // 報錯,重定義錯誤
1         let a = 10;
2         const a = 10; //報錯,重定義錯誤
1        if ( true ) {
2             const a = 10;
3             console.log( a ); //10
4         }
5         console.log( a ); //報錯:a is not defined

[js高手之路]var, let, const詳解