let和var同樣也是用來定義變量,不一樣之處在於let是塊級做用域,只在所定義的塊級做用域中生效,一個花括號即是一個塊級做用域數組
{var a="我是var定義的";let b="我是let定義的"} console.log(a); //我是var定義的 console.log(b); //b is not defined
能夠看出let定義的變量在全局做用域內並無生效數據結構
若是咱們在全局做用域中定義,試一下看在函數或者流程控制語句中是否會輸出函數
let a="我是let定義的" var b=0; while(b<5){b++;console.log(a)}//⑤我是let定義的變量 if(true){console.log(a)}//我是let定義的變量
咱們發現這樣能夠輸出學習
若是咱們反向來一下呢指針
for(let i=0;i<5;i++){ let a="流程控制語句花括號中的let"; var b="流程控制語句花括號中的var"; console.log(i)} //0,1,2,3,4 console.log(a); //a is not defined console.log(b); //流程控制語句中的var
for(var j=0;j<1;j++){ console.log(j)} // 0 console.log(j); //1
咱們發現let定義的變量不會被提高,只要有塊級括號存在,它就只在該塊級中有意義code
若是在函數中呢對象
function test(){console.log(a)}() //報錯
咱們發現並不能輸出內存
咱們能夠得出結論,流程控制語句中的變量均屬於全局變量,可是在流程控制語句中的括號中定義則爲塊級,不會提高爲全局變量作用域
for循環還有一個特別之處,就是設置循環變量的那部分是一個父做用域,而循環體內部是一個單獨的子做用域字符串
for(let i=0;i<3;i++){ let i="abc"; console.log(i)} //abc,abc,abc
let在for循環聲明的變量每一次循環的值都會被引擎內部記下,可是var聲明的變量則會刷新覆蓋掉上一次的值
var a=[]; for(var i=0;i<10;i++){ a[i]=function(){return i};} console.log(a)//[f,f,f,f,f,f,f,f,f,f] a.forEach((e)=>{console.log(e())}) //⑩10
咱們能夠看出,這種方式其實將未執行的函數push進數組了,當每次調用時候發現此刻的i早已經被循環覆蓋掉,最終輸出都爲此刻的i值10
var a=[]; for(let i=0;i<10;i++){ a[i]=function(){return i};} console.log(a)//[f,f,f,f,f,f,f,f,f,f] a.forEach((e)=>{console.log(e())}) //0,1,2,3,4,5,6,7,8,9
可是對於let聲明的變量,每一次引擎都會自動存儲記錄i的值,而不會覆蓋掉,所以每次輸出都是push當時的i值
let不存在變量提高,只有在定義後再使用纔不會報錯
console.log(a);var a=1;//undefined console.log(b);let b=2;//報錯
let具備強制性綁定變量的能力,原先var聲明的變量,當被let從新聲明的時候會被強制性綁定,原先var聲明的全部被let所管轄的塊級做用域裏的變量均被let強制爲本身聲明的值,造成暫時性死區,let所處塊級做用域中let聲明以前的該變量均報錯
var a=1; {console.log(a); let a=2;} //a is not defined
var a=1; {let a=2; console.log(a);//2 }; console.log(a)//1
var a=1; console.log(a);//1 {let a=2; console.log(a);//2 };
let不容許在相同做用域內,重複聲明同一個變量。
{var a=0; let a=1; console.log(a)}//報錯
{let a=0; var a=1; console.log(a)}//報錯
{ let a=2; let a=3; console.log(a)}//報錯
{let a=2; console.log(a); let a=3;}//報錯
上面的最後一個例子能夠看出當再次聲明該變量以前調用的變量都會炸掉
咱們能夠看到let聲明的變量能夠引用塊級做用域外面的函數
let a=f(); function f(){ return 1 } console.log(a)// 1
{let a=f(); console.log(a)// 1 function f(){ return 1 }
const聲明的變量爲永恆變量,不能更改,並且聲明之後必須初始化
const a;//報錯
const b=1; b=2//報錯
const的做用域與let命令相同:只在聲明所在的塊級做用域內有效。
const命令聲明的常量也是不提高,一樣存在暫時性死區,只能在聲明的位置後面使用。
const聲明的常量,也與let同樣不可重複聲明。
const實際上保證的,並非變量的值不得改動,而是變量指向的那個內存地址不得改動。對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,所以等同於常量。但對於複合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指針,const只能保證這個指針是固定的,至於它指向的數據結構是否是可變的,就徹底不能控制了。所以,將一個對象聲明爲常量必須很是當心。
常量foo儲存的是一個地址,這個地址指向一個對象。不可變的只是這個地址,即不能把foo指向另外一個地址,但對象自己是可變的,因此依然能夠爲其添加新屬性。
const foo={}; foo.prop=123; console.log(foo.prop)//123
常量a是一個數組,這個數組自己是可寫的,可是若是將另外一個數組賦值給a,就會報錯。
const a=[]; a.push(1); console.log(a)//[1] console.log(a.length)//1 a=[]//報錯
再來驗證如下引用
var a=1; b=a; console.log(b);//1 a=2; console.log(b)//1 b=3; console.log(a)//2
能夠看出var定義的變量,b=a時候,是直接複製了一份a,並非a的引用
let a=1; b=a; console.log(b);//1 a=2; console.log(b);//1 b=3; console.log(a);//2 console.log(b);//3 var b=4; console.log(b)//4
能夠看出let也同樣
const也是複製一份
const a=1; b=a; console.log(b);//1 b=3; console.log(a);//1 console.log(b);//3 var b=4; console.log(b)//4
還有不少不甚明朗的地方,各位大佬能夠指點一二,互相學習,加深理解