目录

一、概览:变量声明的三种关键方式

二、var:曾经的主角,却留下隐患

        2.1 作用域规则的模糊

        2.2 重复声明与覆盖容易

        2.3 捕获变量的怪异行为

三、let:块级作用域的变量声明

        3.1 块作用域(block-scoped)

        3.2 暂时性死区(TDZ)

        3.3 不能重复声明(同一作用域内)

        3.4 捕获变量在循环中的改进

        3.5 何时使用let

四、const:绑定不变,是另一种承诺

4.1 不可重赋与可变内容的区别

4.2 必须初始化

4.3 何时使用const

五、let vs const:抉择的微妙哲学

六、为何官方推荐let与const多于var

七、总结:让每一个名字都值得被信任


 

        写代码的那一刻,当你敲下:

let message = "Hello, world!";

        你其实在做两件事:给这个名字一个位置,并给这个位置一个承诺

        名字要被使用,承诺要被信任。

        在 JavaScript 的时代,变量声明也许是随意的、模糊的,而在TypeScript的世界里,变量声明被赋予了更多的意义:作用域明确赋值受控未来可读

         本文基于官方文档,从 var、let、const 三种声明方式出发,深入解析它们的语法、作用域、使用场景以及为何 TypeScript 倾向推荐 let 与 const。

        每一个名字背后,都值得我们认真看待。

一、概览:变量声明的三种关键方式

        在 TypeScript(继承ES的语法与语义)中,变量声明主要有三种关键形式:

关键字作用域是否可重新赋值是否可重复声明典型情境
var函数级作用域兼容旧代码、简单脚本
let块级作用域×普通变量、自定义值
const块级作用域××常量、配置、不可变绑定

        接下来,我们分别从var、let、cosnt 三个层面,依次细说它们的特点、问题与用法。

二、var:曾经的主角,却留下隐患

        在JavaScript传统时代,变量声明几乎总是用:

var a = 10;

        这是开发者习以为常的方式。手指敲下var,变量出现了,赋值立刻完成。TypeScript因为是JavaScript的超集,也支持它。

        然而,正因为“方便”,它同时带来了不少潜在问题:

        2.1 作用域规则的模糊

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

f(true);  // 返回 10  
f(false); // 返回 undefined  

        在这个例子里,变量x虽然写在if块里,但在函数体外依然可访问。这是因为var是函数作用域,而不是块作用域

函数作用域:只要在同一个函数里,不管在if、for、while里声明,整个函数都能访问到它。

块作用域:只在它所在的{}内可访问。出了大括号就不能访问。

        这种作用域的不明确,意味着变量“冒出”在你意想之外的地方,隐藏着隐患。

        2.2 重复声明与覆盖容易

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

        注意内部for循环中使用var i再次声明。因为var不区分块里块外,这里是同一个i,覆盖前面的循环控制,极易造成逻辑错误。

        2.3 捕获变量的怪异行为

for (var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);
    }, 100 * i);
}
// 输出十次 “10”

        许多开发者期望输出0,1,2,...9,但由于var i的作用域是同一个,循环结束后i为10,所有回调函数打印的都是10。

        这些问题让var的使用变得危险。TypeScript文档指出,let与const引入,是为了“避免在 JavaScript里常见一些问题”。

三、let:块级作用域的变量声明

        引入let是对var的改进。变量声明不再模糊地漂浮,而是有“块(block)”这个边界。

let hello = "Hello!";

        语法上与var类似,但语义上截然不同。

        3.1 块作用域(block-scoped)

function f(input: boolean) {
    let a = 100;
    if (input) {
        let b = a + 1;
        return b;
    }
    // Error: 'b' 不存在于此处
    return b;
}

        在此例中,b的作用域限于if块内。超出那块就访问不到。相比之下,若使用var b,则可能访问得到,为undefined或旧值。

        3.2 暂时性死区(TDZ)

        在let声明的变量,在其被声明之前,处于所谓 “暂时性死区” 状态——你不能读取或写入它。

a++;        // 不合法:在声明前使用
let a;

        虽然变量“存在”于其被声明的作用域内,但直到声明语句运行之前,不可使用。官方称这是let等块级声明的一个特点。

        3.3 不能重复声明(同一作用域内)

let num = 1;
// let num = 2; // 编译错误:重复声明

        相比var,let在同一作用域中重复声明会报错,从而避免名字被意外覆盖。

        3.4 捕获变量在循环中的改进

        使用let声明循环变量,每次迭代都会产生新的作用域环境,从而避免了var的“所有回调共享同一个变量”的问题:

for (let i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);
    }, 100 * i);
}
// 输出:0,1,2,...9

        官方手册也明确指出,这种行为是let的优势之一。

        3.5 何时使用let

        官方建议:在你预计变量会被重新赋值的情况下,使用let。

        也就是说,当变量需要变化、作用域不需要为全局或函数级、你希望有块级边界的时候,用let是合理的选择。

四、const:绑定不变,是另一种承诺

        如果let是“可以变化的变量”,那么 const 则是“绑定后不再改变”的变量。

const numLivesForCat = 9;

        const与let拥有相同的作用域规则,但最大的差别在于:绑定之后不能再重新赋值

4.1 不可重赋与可变内容的区别

        值得注意的是,const 并不保证变量引用的值完全不可变。它只保证“变量标识符绑定后不再指向新的值”。例如:

const kitty = {
    name: "Aurora",
    numLives: 9
};
kitty.name = "Rory";  // 合法
kitty = { name: "Danielle", numLives: 9 }; // 错误:不能重新赋值

        正如官方文档所述,这并不意味着对象成员不能改变,只是不允许重绑定

4.2 必须初始化

        使用const声明变量时,必须立即进行初始化;不能先声明后赋值。若做类似:

const num: number;
// num = 10; // 错误:const 声明必须初始化

        类型系统会报错。

4.3 何时使用const

        官方建议采用“最小权限原则(least privilege)”:如果你确定一个变量在以后不会被重赋值,那么优先使用 const。

最小权限原则:让代码中的变量、模块、函数、用户仅拥有执行任务所需的最小操作权限。

        这样不仅可读性更好,也让代码逻辑更可预测。

五、let vs const:抉择的微妙哲学

        当你面对“当前变量是否会被修改”这个问题时,其实是在做一种思考模式的切换:是“变化”还是“稳固”?是“可能再赋值”还是“绑定一次”?TypeScript鼓励我们选择更可预测、更可靠的方式。

        大致建议如下:

  • 若你预期变量会被重赋值,使用let
  • 若你一旦赋值就不会变,使用const
  • 避免默认使用var,除非你在兼容旧代码或脚本环境。
  • 在代码审查、团队合作中,const更能显示“这里不会变化”的承诺,使同事或未来维护者一目了然。

        这一选择,看似微小,却折射出更深的编程态度:定义越早、限制越明确,未来越可控

六、为何官方推荐let与const多于var

        从以上分析我们可以归纳出几个关键原因:

  • 作用域更清晰:let与const 使用块级作用域,消除var导致的作用域“泄露”问题。
  • 避免重复声明与覆盖:let防止同一作用域重复声明,减少意外覆盖变量的风险。
  • 提高代码可预测性与可读性:当看到const,你马上知道这个绑定不会再改变;看到let,你知道它可能会。
  • 降低潜在bug:彻底避免var在循环、异步回调中导致的奇怪行为(如变量捕获问题)
  • 团队协作与维护友好:明确变量是否会被修改,有助于团队成员理解、未来维护也更容易。

        因此,TypeScript 文档明确指出:“多数手册内容使用 let 声明。”

七、总结:让每一个名字都值得被信任

        当你选择const,你在说:“这个值一旦设定,就不会动——你可以放心使用它。”

        当你选择let,你在说:“这个值可能改变——我会留意它的变化。”

        而如果你还在用var,可能就意味着:“我暂时不关心它在哪里被访问、被修改、被捕获。”

        这种态度,直接体现在代码可读性、可维护性、健壮性上。

        TypeScript 的变量声明机制,不只是让你“能”写,更让你“应该”写得更好。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐