let和var區別數組
var a = []; for(var i = 0;i<10;i++){ a[i] = function(){console.log(i);}; } a[6]();//10 var b = []; for(let j = 0;j<10;j++){ a[j] = function(){console.log(j);}; } a[5]();//5
第一個var中變量i,在全局範圍內有效,因此全局只有一個變量i,每次循環i的值都會發生改變,而循環內被賦值給數組a的函數內部的console.log(i);裏面的i指向的就是全局的i。全部數組a的成員裏邊的i都是同一個i;致使運行時輸出的是最後一輪的i值也就是10;函數
第二個let中變量i,當前的i只在本輪循環中有效,因此每次循環的i其實都是一個新的變量,因此最後的輸出爲6.(雖然每次i都是從新聲明的,可是js引擎內部會記住上一輪循環的值,初始化本輪的變量i時,就在上一輪循環基礎上進行計算)code
另外for循環還有一個特別之處,就是設置循環變量的那部分是一個父做用域,而循環體內部是一個單獨的子做用域。內存
for(let i = 0;i<3;i++){ let i = '123' console.log(i); } //123 //123 //123
var命令會發生_變量提高_現象,即變量能夠在聲明以前使用,值爲undefined, 而let則會報錯作用域
console.log(a);//undefined var a = 2;
"暫時性死區"(temporal dead zone,簡稱TDZ) 若是在區域塊中存在let和const命令,這個區塊對這些命令聲明的變量從一開始就造成了封閉做用域。凡是在聲明以前就使用這些變量就會報錯。 只要塊級做用域內存在let命令,他所聲明的變量就綁定這個區域,再也不受外部影響。io
var str = 123; if(true){ str = 'abc';//ReferenceError let str; }
代碼中存在全局變量str,可是塊級做用域內let又聲明瞭一個局部變量str,致使後者綁定這個塊級做用域,因此在let聲明變量以前對str賦值會報錯。console
(function foo(x=y,y=2){ return[x,y]; })();//報錯
由於參數x默認等於另外一個參數y,而此時y尚未聲明,屬於‘死區’。for循環
ES5只有全局做用域和函數做用域,沒有塊級做用域致使一些錯誤的產生function
var tmp = new Date(); function f() { console.log(tmp); if (false) { var tmp = 'hello world'; } } f(); // undefined
變量提高致使內層的tmp變量覆蓋了外層的tmp變量。基礎
var s = 'hello'; for (var i = 0; i < s.length; i++) { console.log(s[i]); } console.log(i); // 5
i泄露成了全局變量