第二章 let和const的命令

weixin_33807284發表於2017-11-30

2.1 let命令

2.1.1 基本用法

let宣告的變數,只在let命令所在的程式碼塊內有效

{
    let a = 10;
    var b = 1;
}

a // ReferenceError: a is not defined
b // 1

for 迴圈的計數器,就很適合使用let命令

for(let i = 0; i < arr.length;i++){}

i  // ReferenceError: a is not defined

2.1.2 不存在變數提升

let 不像 var 那樣會發生 “變數提升” 現象,所以變數一定要在宣告後使用,否則報錯。

console.log(foo);  ==> undefined
console.log(bar);  ==> ReferenceError: bar is not defined

var foo = 2;
let bar = 2

2.1.3 暫時性死區

只要塊級作用域記憶體在let命令,它所宣告的變數就“繫結”這個區域,不再受外部的影響。

var tmp = 123;

if( true ){
    tmp = 'abc'; // ReferenceError: tmp is not defined
    let tmp;
}

ES6明確規定,如果區塊中存在letconst命令。這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域。凡是在宣告之前就使用這些變數,就會報錯。

“暫時性死區”也意味著 typeof 不再是一個百分之百安全的操作

typeof x // ReferenceError: x is not defined
let x

這樣的設計是為了讓大家養成良好的程式設計習慣,變數一定要在宣告後使用,否則就會報錯。

ES6規定暫時性死區和letconst語句不出現變數提升,主要是為了減少執行時的錯誤,防止在變數宣告前就使用這個變數,從而導致意料之外的行為。

2.1.4 不允許重複宣告

let 不允許在相同作用域內,重複宣告同一個變數

//報錯
function func(){
    let a = 10;
    var a = 1;
}

//報錯
function func(){
    let a = 10;
    lat a = 1;
}

//報錯
function func(arg){
    let arg; 
}

2.2 塊級作用域

2.2.1 為什麼需要塊級作用域?

(1) 內層變數可能會覆蓋外層變數

var tmp = new Date();

function f(){
    console.log(tmp)
    if( false ){
        var tmp = 'hello world'
    }
}

f() ==> undefined

tmp變數提升覆蓋了tmp原始值

(2) for迴圈中的迴圈變數洩露為全域性變數

2.2.2 ES6的塊級作用域

ES6中的letconst 實現了塊級作用域

塊級作用域的出現,使得廣泛應用的立即執行匿名函式(IIFE)不再必要了

// IIFE 寫法
(function(){
    var tmp = '';
}());

//塊級作用域寫法
{
    let tpm = '';
}

2.2.3 塊級作用域與函式宣告

ES5規定,函式只能在頂層作用域和函式作用域之中宣告,不能在塊級作用域宣告,所以,以下兩種都是錯誤的:

//情況1:
if( true ){
    function f(){}
}

//情況2
try{
    function f(){}
} catch (e) {
    
}

但是,瀏覽器沒有遵守這個規定,不會報錯。不過,在嚴格模式下,會報錯。

ES6 引入了塊級作用域,明確允許在塊級作用域之中宣告函式。

應該避免在塊級作用域內宣告函式,如果確實需要,也應該寫成函式表示式,而不是函式宣告語句。

//函式宣告語句
{
    let a = 'secret';
    function f(){
        return a; 
    }
}

//函式表示式
{
    let a = 'secret';
    let f = function (){
        return a;
    }
}

2.3 const命令

const 宣告一個只讀的常量,一旦宣告,常量的值就不能改變,

const PI = 3.1415;

PI = 3 // 報錯

const 一旦宣告變數,必須立即初始化,不能留到以後賦值
const foo //報錯 Missing initializer in const declaration

const的作用域與let命令相同,只在宣告所在的塊級作用域內有效。

if ( true ){
     const MAX = 5;
}

MAX //報錯

const 也沒有變數提升,存在暫時性死區,只能在宣告的位置後面使用。

if( true ){
    console.log(MAX);  // ReferenceError: MAX is not defined
    const MAX = 5;
}

const 不可重複宣告

var message = 'hello';

const message = 'goobye' //報錯  Missing initializer in const declaration

2.4 全域性物件的屬性

未宣告的全域性變數,自動成為全域性物件的window屬性,這被認為是js語言最大的設計敗筆之一。

ES6為了改變這一點,

一方面規定:為了保持相容性,var 命令和 function 命令宣告的全域性變數,依舊是全域性物件的屬性。

var a = 1;
window.a ==> 1

function f(){ console.log('a') }
widnow.f() ==> 'a'

另一方面規定:let命令、const命令、class命令宣告的全域性變數,不屬於全域性物件的屬性。

也就是說,從ES6開始,全域性變數將逐步與全域性物件的屬性脫鉤

let b = 1;
window.b ==> undefined

相關文章