var、let 用於聲明變量,const 用於聲明常量。都可以在一個語句中聲明多個變量,變量以英文逗號分開。
var name1 = "Lee1",
age1 = 26,
job1 = "teacher1";
let name2 = "Lee2",
age2 = 26,
job2 = "teacher2";
const name3 = "Lee3",
age3 = 26,
job3 = "teacher3";
console.log(name1,age1,job1);
console.log(name2,age2,job2);
console.log(name3,age3,job3);
輸出:
1、var關鍵字
存在變量提升:var 聲明的函數及變量的聲明都將被提升到函數的最頂部;變量可以先使用再聲明,但變量的值並不會提升。
console.log(num)//undefined
var num=20;
這裏輸出 num 爲 undefined:1、因爲變量提升,所以並不會報錯 (ReferenceError);2、因爲變量的值不會提升,所以輸出的是默認值undefined。
2、let關鍵字
1)使用let關鍵字聲明的變量具有塊級作用域:由 { } 包括,if語句和for語句裏面的{ }也屬於塊作用域,for循環中( ) 中用let 聲明的變量與此for循環綁定,在for循環外訪問不到。
for(let i=0;i<2;i++){
console.log(i);
}
console.log("----")
console.log(i);
輸出:
2)使用let關鍵字聲明的變量不存在變量提升。
console.log(n);
let n=10;
輸出:
3)使用let關鍵字聲明的變量具有暫時性死區特性:在塊級作用域內聲明變量,這個變量會和這個塊級作用域綁定
var num=10;
if(true){
console.log(num); //這裏會報錯,
//因爲在塊級作用域聲明變量,這個變量會和這個塊級作用域綁定,這裏與外面的num無關了。
let num =20;
}
輸出:
4)不允許重複聲明:let 不允許在相同作用域內重複聲明同一個變量。
function foo(){
let a=0;
var a=1;
}
foo();
輸出:
3、const關鍵字
作用:聲明常量(內存地址不能變化的量)。
1)具有塊級作用域
2)不存在變量提升。
3)具有暫時性死區特性。
4)聲明常量必須賦值。
5)常量賦值後,值不能更改。——對於複雜類型數據,它內部的值是可以更改的,但是不能對它重新賦值,即數據值本身不能更改,因爲重新賦值更改了該數據的內存地址。
const num=20;
num=10;
console.log(num);
輸出:
const obj={
name:'劉亦菲',
age:18
}
obj.name='趙靈兒'
console.log(obj);
obj={
name:'李逍遙',
age:21
}
console.log('------');
console.log(obj);
輸出:
這裏的‘------’都未輸出,是因爲到 obj 賦新值時就報錯了。
6)如果存儲的關鍵字不需要變化,儘量使用 const 關鍵字,比如函數定義等。因爲 const 關鍵字聲明的值不需要變化,JavaScript 解析引擎不需要實時監控值的變化,所以 const 比 let 效率高。
總結:
var |
let |
const |
函數級作用域 |
塊級作用域 |
塊級作用域 |
變量提升 |
不存在變量提升 |
不存在變量提升 |
值可更改 |
值可更改 |
值不可更改 |
沒有暫時性死區特性 | 具有暫時性死區特性 | 具有暫時性死區特性 |
聲明時不必賦值 | 聲明時不必賦值 | 聲明時必須賦值 |
經典面試題
var arr=[]
for(var i=0;i<2;i++){
arr[i]=function(){
console.log(i);
}
}
arr[0](); //2
arr[1](); //2
分析:在函數內部沒有定義變量 i,函數執行時在自己的作用域找不到變量 i 值,根據作用域鏈查找原則,要向上一層作用域查找,這裏的上一層作用域就是全局作用域,有i。函數執行時,循環早已結束,所以 i 的值是不滿足循環條件的值,即 i = 2,所以函數執行輸出的是2。
let arr=[]
for(let i=0;i<2;i++){
arr[i]=function(){
console.log(i);
}
}
arr[0](); //0
arr[1](); //1
分析:每次循環都會產生一個塊級作用域,每個塊級作用域中的變量都不同,函數執行時輸出的是自己上一級(循環產生的塊級作用域)作用域下的 i 值。