变量声明
在 TypeScript 中,变量的声明和作用域规则与 JavaScript 相似,但增加了一些额外的类型检查和语法糖。下面详细介绍 TypeScript 的变量声明、作用域规则、捕获变量的怪异之处、块作用域、重定义及屏蔽、块级作用域变量的获取等内容。
1. 变量声明
TypeScript 支持 var
、let
和 const
三种变量声明方式。
var 声明
var
声明的变量具有函数作用域或全局作用域。
function varTest() {
var x = 1;
if (true) {
var x = 2; // 同一个变量
console.log(x); // 2
}
console.log(x); // 2
}
let 声明
let
声明的变量具有块级作用域,避免了 var
变量声明带来的一些问题。
function letTest() {
let x = 1;
if (true) {
let x = 2; // 不同的变量
console.log(x); // 2
}
console.log(x); // 1
}
const 声明
const
声明的是常量,必须初始化且不可重新赋值。它也是块级作用域。
const y = 1;
// y = 2; // 错误: 不能重新赋值
2. 作用域规则
TypeScript 中的作用域规则分为全局作用域、函数作用域和块级作用域。
全局作用域
在最外层定义的变量具有全局作用域。
let globalVar = "I am global";
function f() {
console.log(globalVar); // I am global
}
函数作用域
在函数内部定义的变量具有函数作用域,只在函数内部可见。
function funcScope() {
let funcVar = "I am in function";
console.log(funcVar); // I am in function
}
// console.log(funcVar); // 错误: funcVar 在此作用域不可见
块级作用域
用 let
或 const
声明的变量在块级作用域内可见。
function blockScope() {
if (true) {
let blockVar = "I am in block";
console.log(blockVar); // I am in block
}
// console.log(blockVar); // 错误: blockVar 在此作用域不可见
}
3. 捕获变量的怪异之处
在 JavaScript 中,var
声明的变量有变量提升和函数作用域,这可能导致一些意想不到的行为。
for (var i = 0; i < 10; i++) {
setTimeout(() => console.log(i), 100); // 输出10次 10
}
使用 let
可以避免这个问题,因为它具有块级作用域。
for (let i = 0; i < 10; i++) {
setTimeout(() => console.log(i), 100); // 输出 0 到 9
}
4. 重定义及屏蔽
在 TypeScript 中,可以重定义同一作用域内的变量,这可能导致意想不到的行为。使用 let
或 const
可以避免这种情况。
function redeclareVar() {
var x = 10;
var x = 20; // 正确
console.log(x); // 20
}
function redeclareLet() {
let x = 10;
// let x = 20; // 错误: 不能在同一作用域内重定义
console.log(x);
}
5. 块级作用域变量的获取
在嵌套的块级作用域中,内层作用域可以访问外层作用域的变量。
function blockScopeAccess() {
let outer = "outer";
{
let inner = "inner";
console.log(outer); // outer
}
// console.log(inner); // 错误: inner 在此作用域不可见
}
在块级作用域中,如果内层作用域中有与外层作用域同名的变量,内层变量会屏蔽外层变量。
function scopeShadowing() {
let x = "outer";
{
let x = "inner";
console.log(x); // inner
}
console.log(x); // outer
}
6. 使用闭包捕获变量
在使用闭包时,要特别注意变量的捕获方式。可以通过立即执行函数表达式(IIFE)来创建新的作用域,以捕获每次迭代的变量。
for (var i = 0; i < 10; i++) {
((j) => {
setTimeout(() => console.log(j), 100); // 输出 0 到 9
})(i);
}
总结
TypeScript 的变量声明和作用域规则提供了更严格的类型检查和更明确的作用域控制,避免了许多 JavaScript 中常见的问题。通过理解和使用这些规则,可以编写更可靠和可维护的代码。
参考
https://www.typescriptlang.org/docs/handbook/variable-declarations.html