[js高手之路]var, let, const詳解
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 returna; 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詳解