TypeScript學習筆記—變量的聲明

從var聲明提及

一直以來咱們都是經過var關鍵字定義JavaScript變量。typescript

var a = 10;

var聲明的變量var聲明能夠在包含它的函數,模塊,命名空間或全局做用域內部任何位置被訪問。
好比在其它函數內部訪問相同的變量:函數

function f() {
    var a = 10;
    return function g() {
        var b = a + 1;
        return b;
    }
}
var g = f();
g(); // returns 11;

這些做用域規則可能會引起一些錯誤。code

  • 第1個問題就是屢次聲明同一個變量並不會報錯。好比下面這個例子:
function sumMatrix(matrix: number[][]) {
    var sum = 0;
    for (var i = 0; i < matrix.length; i++) {
        var currentRow = matrix[i];
        for (var i = 0; i < currentRow.length; i++) {
            sum += currentRow[i];
        }
    }
    return sum;
}
sumMatrix([[1,2],[3,4]])

通常認爲,運行的結果應該爲10。但結果並不是如此,由於全部i都引用相同的函數做用域內的變量,裏層的for循環會覆蓋變量i,因此如今的結果是3而不是10。因此使用var聲明時,它不在意你聲明多少次你只會獲得1個。ip

  • setTimeout中的異常

看下面這段代碼:ci

for (var i = 0; i < 10; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}

咱們指望的結果是:每隔100*i毫秒打印出1個數字,順序爲1-10,但實際打印出的所有都是10。這是由於setTimeout在若干毫秒後執行一個函數,而且是在for循環結束後。 for循環結束後,i的值爲10。 因此當函數被調用的時候,它會打印出 10!咱們不得不利用一個當即執行函數解決這個問題:作用域

for(var i = 0; i < 10; i++){
    (function(i){setTimeout(()=>console.log(i), i * 100);})(i)
}

var聲明的變量帶給咱們這麼多困擾,因此在typescript中加入了let對變量進行聲明。get

let聲明

let與var的寫法一致:input

let hello = "Hello!";

let聲明的變量和var聲明的變量有不少不一樣之處,let解決了var變量帶來的困擾。it

  • 塊做用域

當用let聲明一個變量,它使用的是塊做用域。 不一樣於使用 var聲明的變量那樣能夠在包含它們的函數外訪問,塊做用域變量在包含它們的塊或for循環以外是不能訪問的。io

function f(input: boolean) {
    let a = 100;
    if (input) {
        let b = a + 1;
        return b;
    }
    return b;
}

在上面代碼中,a能夠在if語句中被訪問,由於a在函數語句中聲明,在if語句以外,而b就不能在if語句塊以外被訪問,由於b是在if語句塊中被聲明的。
在catch語句裏聲明的變量也具備一樣的做用域規則。

try {
    throw "oh no!";
}
catch (e) {
    console.log("Oh well.");
}
console.log(e);        //error

在catch語句塊外,e是不能被訪問的。

在let語句聲明以前訪問let聲明的變量,結果爲undefined。

function foo() {
    // okay to capture 'a'
    return a;
}
console.log(foo());            //
let a = 10;
  • 重定義及屏蔽

var聲明時,不論你聲明多少次,你只會獲得1個。

var x = 10;
console.log(x);        //10
var x = 20;
console.log(x);        //20

let聲明,須要遵循塊做用域規則,在一個塊做用域中重複聲明變量會產生錯誤提示,另外一個用var聲明也不容許。

function g() {
    let x = 100;
    var x = 100; // error: can't have both declarations of 'x'
}

塊級做用域變量能夠用函數做用域變量來聲明。 可是塊級做用域變量須要在明顯不一樣的塊裏聲明。

function f(condition, x){
    if(condition){
        let x = 100;
        return x;
    }
    return x;
}
console.log(f(true, 0));        //100
console.log(f(false, 0));       //0

在一個嵌套做用域裏引入一個新名字的行爲稱作屏蔽。 它是一把雙刃劍,它可能會不當心地引入新問題,同時也可能會解決一些錯誤。 例如,假設咱們如今用 let重寫以前的sumMatrix函數。

function sumMatrix(matrix: number[][]){
    let sum = 0;
    for(let i = 0; i < matrix.length; i++){
        let current = matrix[i];
        for(let i = 0; i < current.length; i++){
            sum += current[i];
        }
    }
    return sum;
}
console.log(sumMatrix([[1,2],[3,4]]));      //10

此次能夠獲得正確的結果10,由於內層循環中的i屏蔽了外層循環中的i。但這種寫法是不推薦的。

  • 塊級做用域變量的獲取
function theCityThatAlwaysSleeps() {
    let getCity;
    if (true) {
        let city = "Seattle";
        getCity = function() {
            return city;
        }
    }
    return getCity();
}

上面這段代碼能夠正常執行。由於咱們已經在city的環境裏獲取到了city,因此就算if語句執行結束後咱們仍然能夠訪問它。
當let聲明出如今循環體裏時擁有徹底不一樣的行爲,針對每次迭代都會建立一個新做用域。因此在 setTimeout例子裏咱們僅使用let聲明就能夠了。

for(let i = 0; i < 10; i ++){
    setTimeout(()=>console.log(i), i*100);
}

會輸出與預料一致的結果:1 2 3 4 5 6 7 8 9

const 聲明

const 聲明是聲明變量的另外一種方式。它們與let聲明類似,可是就像它的名字所表達的,它們被賦值後不能再改變。

const numLivesForCat = 9;

它們擁有與 let相同的做用域規則,可是不能對它們從新賦值。

const kitty = {
    name: "Aurora",
    numLives: numLivesForCat,
}
// Error
kitty = {
    name: "Danielle",
    numLives: numLivesForCat
};

但const變量內部的狀態仍是能夠改變的。

const kitty = {
    name: "Aurora",
    numLives: numLivesForCat,
}
// all "okay"
kitty.name = "Rory";
kitty.name = "Kitty";
kitty.name = "Cat";
kitty.numLives--;

let與const的區別

最後,說說let與const的區別,引用官網的建議:

使用最小特權原則,全部變量除了你計劃去修改的都應該使用const。 基本原則就是若是一個變量不須要對它寫入,那麼其它使用這些代碼的人也不可以寫入它們,而且要思考爲何會須要對這些變量從新賦值。 使用 const也可讓咱們更容易的推測數據的流動。
相關文章
相關標籤/搜索