ES6入門 (一)
let 和 const 命令
- 定義:let 和 const 都是ES6 當中聲明變量的
關鍵字
let
定義
let 用法與var 相似
注意事項
塊級作用域
我們使用let 會創建一個塊級作用域,這個變量只能在這個塊級作用域當中使用。那么問題來了,什么是塊級作用域呢?在我們學習js的時候相信大家都知道什么是 局部作用域
什么是 全局作用域
。下面我們例子說明一下
<script>
let a = 5; //當我們在全局范圍內聲明一個變量的時候,這個變量的塊級作用域就是全局作用域
function fn1(){
let b = 10 //當我們在局部范圍內聲明一個變量,他的塊級作用域就是局部作用域
}
</script>
- ES5當中 內存變量可能會覆蓋外層變量
var a = 'abc';
function f() {
// 函數內部變量提升 相當於 var a 的聲明
console.log(a);
if(false) {
var a = 'hello,world'
}
}
f() // undefined
上面代碼的原意是,if
代碼塊的外部使用外層的tmp
變量,內部使用內層的tmp
變量。但是,函數f
執行后,輸出結果為undefined
,原因在於變量提升,導致內層的tmp
變量覆蓋了外層的tmp
變量。
- 用來計數的循環變量泄露成全局變量
var s = 'hello';
for(var i=0;i<s.length;i++){
console.log(s[i])
}
console.log(i) //5
- ES5中 函數只能在頂層的作用域和函數作用域之中聲明,不能在塊級作用域當中聲明。而ES6當中
允許
在塊級作用域之中聲明函數。但是函數聲明語句的行為類似於let
,在塊級作用域之外不可引用
不存在變量提升
如果你已經學過 js 並且有一定的js 基礎 那么你對 變量提升
一定不陌生。我們都知道如果按正常邏輯,我們必須聲明一個變量,然后才應該可以使用他,而變量提升就可以讓我們在聲明變量之前就使用這個變量(只是不會報錯)
變量提升簡單來說:就是在js 代碼解析的過程當中 我們會把所有的聲明的變量提升到這個變量所在作用域的第一行,也就是說我們在給變量賦值之前使用變量的時候不會報錯,因為變量提升讓變量的聲明體現到了代碼解析的最前面。
而我們使用let 聲明變量的時候,不存在變量提升。也就是說我們在聲明這個變量之前不可以使用這個變量否則就會報錯
// 變量提升 相當於 var a 提前聲明了一個變量 只有經歷賦值操作才可以有值
console.log(a) // undefined
var a = 2
console.log(a) // 2
console.log(b) // 報錯
let b = 2
console.log(b) // 2
let的特點就是存在暫時性死區
只要塊級作用域內存在 let
命令,它所聲明的變量就 “綁定” (binding)
這個區域,不再受外部的影響。
var a = 10;
if (true) {
a = 5; // ReferenceError
let a;
}
在這個代碼中, 存在一個全變量 a
, 但是在 if
塊級作用域內又聲明了一個局部變量a,導致局部變量a被綁定在這個塊級作用域,所以在let
聲明變量前,使用這個局部變量都會報錯。
ES6 明確規定,如果區塊中存在let
和const
命令,這個區塊對這些命令聲明的變量,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量,就會報錯。
總之,在代碼塊內,使用let
命令聲明變量之前,該變量都是不可用的。這在語法上,稱為“暫時性死區”(temporal dead zone,簡稱 TDZ)
if(true) {
a = 'abc'; // ReferenceError
console.log(a) // ReferenceError
let a ; //遇到了變量的聲明 暫時性死區結束
console.log(a) //已經遇到了變量的聲明,這個時候打印他 a的值是 undefined
a = 123;
console.log(a) // 結果 123
}
特殊情況的暫時性死區 之 ES6函數存在默認值情況
function fn1(x=y,y=2) {
return [x,y]
}
fn1() //報錯
如果你是初次介紹es6 我可以簡單給你先介紹一下es6中函數存在默認值的情況。函數的默認值呢,是在我們使用函數並且沒有給函數傳遞實參的時候,這時他的參數的值就等於我們給這個參數設置的默認值
在上述代碼中 參數x
默認值等於另一個參數 y
但是在這個時候 y
還沒有聲明,屬於 暫時性死區。
function fn1(x=2,y=5) {
return [x,y]
}
fn1() // //[2,5] 因為我們沒有給這個函數傳遞實參 所以參數的默認值就起了作用
fn1(3) // [3,5]
fn1(3,4) //[3,4]
默認參數的作用域
一旦設置了參數的默認值,函數進行聲明初始化的時候,參數會形成一個單獨的作用域。等到初始化結束,這個作用域就會消失 。
var x = 1;
function f(x,y=x) {
console.log(y)
}
f(2) // 2
在上述代碼當中,參數y
的默認值等於變量x
。調用這個函數的時候,參數形成了一個單獨的作用域 ,在這個作用域里面,函數的一個參數指向的是調用這個函數傳遞的實參2
let x = 2
function f1(y=x){
let x = 3;
console.log(y)
}
f1() // 2
在上述代碼中同樣涉及到一個高級概念 作用域鏈
。與上面例子一樣,調用這個函數的時候y=x 形成了一個單獨的作用域他是局部作用域,因為在這里x的值不存在,所以根據作用域鏈,他會向上一層作用域尋找x直到找到他 所以這個例子中 參數y的默認值x 是全局作用域當中聲明的變量x
不允許重復聲明變量
function fn2() {
let a = 10;
let a = 1; // 報錯
}
fn2()
function fn3(x) {
let x;
}
fn3() // 報錯
function fn4(x) {
{
let x ;
}
}
fn4() // 不報錯
const 關鍵字
定義:
const
聲明一個只讀的常量。一旦聲明,常量的值就不能改變。
注意事項
const
命令聲明的常量也是不提升,同樣存在暫時性死區,只能在聲明的位置后面使用。
const命令的本質
const
實際上保證的,並不是變量的值不得改動,而是變量指向的那個內存地址所保存的數據不得改動。對於簡單類型的數據(數值、字符串、布爾值),值就保存在變量指向的那個內存地址,因此等同於常量。但對於復合類型的數據(主要是對象和數組),變量指向的內存地址,保存的只是一個指向實際數據的指針,const
只能保證這個指針是固定的(即總是指向另一個固定的地址),至於它指向的數據結構是不是可變的,就完全不能控制了。因此,將一個對象聲明為常量必須非常小心。
const foo = {};
// 為 foo 添加一個屬性,可以成功
foo.prop = 123;
foo.prop // 123
// 將 foo 指向另一個對象,就會報錯
foo = {}; // TypeError: "foo" is read-only