变量与常量
在 JavaScript 中,曾以 var
关键字来声明变量,但这种声明方式存在很多问题。从 ECMAScript 6 开始,ECMAScript 中引入了新的 let
关键字(用来声明变量),以及新的 const
关键字(用来声明常量)。在 TypeScript 中,也推荐使用 let
和 const
关键字来进行声明,不再使用落后的 var
关键字(var
关键字存在许多问题,感兴趣的读者可以自行搜索)。接下来,将分别介绍 let
和 const
关键字的用法。
let关键字
在 TypeScript 中使用 let
关键字声明变量,语法如下。
let 变量名称:数据类型;
前面的示例都使用 let
关键字来声明变量,因此这里不再讲述其基本用法。接下来,将介绍 let
关键字的一些使用要点。
块级作用域
使用 let
关键字定义的变量具备块级作用域,在作用域外无法使用该变量。
在 TypeScript 中,以左花括号 “{
” 开头、以右花括号 “}
” 结尾形成代码块,将多条语句组合到一个代码块中,将其视作一个整体来组织、管理和运行。
代码块将决定变量的作用域,决定其使用范围究竟是整个 TypeScript 程序、某个类还是某个局部代码块。块级作用域可以简单理解为变量的生效范围在它所定义的代码块中。例如,在以下代码中,变量 b
在 if
代码块中定义,因此它的作用域仅在此代码块中,在代码块之外将无法使用。
if (true) {
let b: number = 30;
console.log(b);
}
//编译错误:找不到名称"b"。ts(2304)
console.log(b);
上层作用域内的变量可以在下层作用域内直接使用。如果在下层作用域中定义了同名变量,在引用此变量时,只会引用下层作用域的变量,上层作用域的同名变量在此作用域内将暂时失效,无法使用或修改,示例代码如下。
if (true) {
//块级作用域1
let b: number = 30;
{
//块级作用域2
//此作用域声明了同名变量b,因此在此作用域内使用该变量时,只会使用此作用域内的变量b,上层作
//用域的变量b将会暂时失效
let b: number = 20;
console.log(b); //输出20
}
console.log(b); //输出30
{
//块级作用域3
//由于此作用域内没有声明同名变量,因此使用了上层作用域的变量b,输出30
console.log(b);
}
}
全局作用域
全局作用域是最上层的作用域,在以左花括号 “{
” 开头、以右花括号 “}
” 结尾形成的代码块之外声明的变量都位于全局作用域中,在所有作用域都可以访问全局作用域的变量,示例代码如下。
//全局作用域变量a
let a: number = 1;
if (true) {
console.log(a);
}
暂时性死区
在用 let
关键字声明某个变量之前,该变量无法使用,这种机制称为暂时性死区。例如,以下代码将直接引起编译错误。
//编译错误:声明之前已使用的块范围变量"a"。ts(2448)
a = 2;
//编译错误:声明之前已使用的块范围变量"a"。ts(2448)
console.log(a);
let a: number = 1;
以下代码虽然不会引起编译错误,但在运行时会报错。
testLog();
function testLog() {
console.log(b);
}
let b: number = 2;
输出结果如下。
> Uncaught ReferenceError: Cannot access 'b' before initialization
注意,在下层作用域中声明同名变量,会使得上层作用域的同名变量在整个下层作用域中失效,因此在下层作用域声明该同名变量之前,此变量将由于暂时性死区而无法使用,示例代码如下。
let c: number = 1;
function testNumber() {
//编译错误:声明之前已使用的块范围变量"c"。ts(2448)
console.log(c);
let c: number = 2;
}
testNumber(); // Block-scoped variable 'c' used before its declaration.
const关键字
在 TypeScript 中使用 const
关键字声明常量,语法如下。
const 常量名称:数据类型 = 初始值;
示例代码如下。
const a: number = 1;
const b: boolean = true;
const c: string = "hello";
const d: bigint = 6n;
用 const
关键字声明的常量和用 let
关键字声明的变量一样,都具备块级作用域、全局作用域、暂时性死区并且禁止重复声明,但变量和常量有一个关键的区别,即常量只能在声明时赋值,且赋值后不可更改,否则会引起编译错误,示例代码如下。
//编译错误:必须初始化 "const" 声明。ts(1155)
const a: number;
const b: string = "hello";
//编译错误:无法分配到 "b",因为它是常数。ts(2588)
b = "world";
具体该使用 let
关键字还是 const
关键字,应该视当时的情况而定。如果一个变量的值在声明后不允许修改,那么应该使用 const
关键字;如果允许修改但不需要修改,那么也应该使用 const
关键字;在其他情况下,则建议使用 let
关键字。