ES6學習筆記(一)————————————–let和const

王煒發表於2019-02-16

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定義的變數不會被提升,只要有塊級括號存在,它就只在該塊級中有意義

如果在函式中呢

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

還有很多不甚明朗的地方,各位大佬可以指點一二,互相學習,加深理解

相關文章