TS 小记(4)变量声明

324 阅读4分钟

变量

变量用于表示程序中的数据。TypeScript 中的变量遵循如下语法规则:

  • 变量名可以包含数字和字母
  • 除了下划线 _ 和美元符号 $ 外,不能包含其他特殊字符,如空格
  • 变量名不能以数字开头

声明

需要先声明一个变量,才可以使用它。在 TypeScript 中,我们有三个关键词可以用于声明变量,分别是 varletconst。我们先以 var 为例来介绍声明变量的几种写法,再来介绍这三个关键字之间的差异。

  1. 声明变量名、变量类型和初始值,这是最全的一种声明方式
var [变量名]: [变量类型] = 初始值;
// Eg
var username: string = "Owen";

TypeScript 声明变量类型的方式和 Kotlin 相同,在变量名后面加 : 变量类型

  1. 申明变量名和类型,没有初始值,这时候变量的值为 undefined
var [变量名]: [变量类型];
// Eg
var username: string;
console.log(username); // 输出 undefined,TypeScript 编译器会提示一个错误信息:在赋值前使用了变量“username”。
  1. 声明变量名和初始值,不显式指定类型,编译器会根据初始值智能推断变量的类型。
var [变量名] = 初始值;
// Eg
var lastname = "Lee";
lastname = 1;         // 报错:不能将类型“number”分配给类型“string”。 
  1. 只声明变量名,不指定类型和初始值,此时编译器只能推断出该变量类型为 any
var [变量名];
// Eg
var lastname;              // 类型为 any
lastname.canBeExist();     // 编译器不会对 any 类型调用的方法做类型检查

var、let 和 const

var

var 是最常使用的声明变量的关键字,但它的规则却有一点奇怪,不了解的情况下有可能踩坑。

var 声明的变量可以在包含它的函数、模块、命名空间或全局作用域内部任何位置被访问,包含它的代码块对此没有限制作用。这个特性被称为 var 作用域函数作用域

举个例子:

function f(shouldInitialize: boolean) {
    if (shouldInitialize) {
        var x = 10;
    }

    return x;
}

f(true);  // returns '10'
f(false); // returns 'undefined'

变量 x 声明在 if 语句中,却可以在语句外访问它。

这样的作用域规则可能会引发一些错误,比如,多次声明同一个变量不会报错:

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;
}

这个例子中,外层循环和里层循环都定义了变量 i,里层会覆盖外层的变量 i,因为所有的 i 都引用相同的函数作用域内的变量。这些问题很容易在 Code Review 中被忽略,引起 Bug。

除此之外,var 在变量获取时也有一些奇怪之处,这里不赘述。

let

正是因为 var 奇怪的规则以及可能引起的一些问题,才引入了 let 这个关键字。let 用来声明变量的语法和 var 一致。

let [变量名]: [变量类型] = 初始值;
// Eg
let username: string = "Owen";

let 和 var 的区别在于语义。当使用 let 声明一个变量,它使用的是 词法作用域块作用域。不像 var 声明的变量可以再包含它们的函数外访问,let 声明的变量在包含它们的块之外是不能访问的,这和其他编程语言变量的作用域类似。

function f(input: boolean) {
    let a = 100;

    if (input) {
        // Still okay to reference 'a'
        let b = a + 1;
        return b;
    }

    // Error: 'b' doesn't exist here
    return b;
}

上面这个例子中,变量 a 的作用域是整个函数体,变量 b 的作用域是 if 语句内部,在 if 语句外就无法访问 b。

const

const 关键字用来声明不可变的变量,它一旦赋值后就不能再改变,这里不能改变指的是引用不能变。const 的作用域和 let 一样。

const username: string = "owen";
username = "sam"; // Error

const person = {
  firstname: "owen",
  lastname: "lee";
}

person = {
  firstname: "sam",
  lastname: "liu"
};         // Error

// 但 const 变量内部的状态是可以改变的
person.firstname = "sam";      // OK
person.lastname = "liu";       // OK

推荐使用 let 代替 var,避免一些代码上的潜在风险,并且尽可能使用 const 来声明不可变变量,防止变量被随意赋值。


开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天,点击查看活动详情