Appearance
什么是TypeScript的变量
TypeScript的变量声明方式与JavaScript一致,使用var、let、const关键字声明变量。三个关键字的用法和JS几乎一致,主要是作用域,和变量赋值上的差异。下面我们将详细介绍
TypeScript的变量声明方式与JavaScript差异
TypeScript 变量声明与 JavaScript 的主要差异在于 TypeScript 提供了静态类型系统,而 JavaScript 是动态类型的。TypeScript 通过引入静态类型系统为 JavaScript 带来了更强的类型安全性,这有助于在开发过程中减少错误并提高代码的可维护性。然而,这也增加了学习曲线,因为开发者需要理解并掌握这些额外的类型概念。
因为TypeScript是JavaScript的超集,所以它本身就支持let和const。 下面我们会详细说明这些新的声明方式以及为什么推荐使用它们来代替var。
过去的J avaScript代码中,我们通常会使用var来声明变量,但是这会使得代码中包含很多全局变量,这可能会导致一些意想不到的问题。在TypeScript中,我们推荐使用let和const来声明变量。
如何声明
在JavaScript中,var声明的变量是函数作用域的,如果在函数内部声明,那么这个变量就只能在函数内部访问。而在TypeScript中,var声明的变量是块级作用域的,如果在函数内部声明,那么这个变量只能在函数内部访问。
typescript
let isDone: boolean = false;
let age: number = 30;
let name: string = "Alice";
或者,如果你只是声明变量而不立即赋值,可以省略 = value 部分:
ts
let variableName: Type;
在后续的代码中,你可以给这个变量赋值:
ts
variableName = someValue;
变量声明的注意事项
遵循这些注意事项可以帮助你编写类型安全、易于维护的 TypeScript 代码。记住,类型注解是 TypeScript 提供的一项强大特性,它们可以帮助你捕获类型错误,并提高代码的可读性和可维护性。
类型注解:TypeScript 强制你使用类型注解来明确变量的类型。如果变量在声明时没有初始化,TypeScript 会根据类型注解来推断后续赋值的类型。
类型推断:如果声明变量时直接赋了值,而没有显式地指定类型注解,TypeScript 会使用类型推断来确定变量的类型
ts
let inferredNumber = 42; // TypeScript 会推断出 inferredNumber 的类型是 number
const 与 let:使用 const 声明的变量是常量,一旦赋值后就不能再修改。使用 let 声明的变量可以在其生命周期内被重新赋值。
避免使用 var:在 TypeScript 中,最好避免使用 var 关键字来声明变量,因为 var 存在变量提升(hoisting)的问题,并且其作用域不是块级的,这可能导致一些不易察觉的错误。
类型兼容性:在赋值给变量时,必须确保值的类型与变量的类型注解兼容。如果类型不兼容,TypeScript 会在编译时报错。
可选的类型注解:在某些情况下,你可能想要保持变量的类型灵活性,这时可以使用 any 类型,但应当谨慎使用,因为它会绕过 TypeScript 的类型检查。
数组和对象类型:声明数组和对象时,需要指定数组元素的类型或对象的结构。
ts
let numbers: number[] = [1, 2, 3]; // 数组类型
let person: { name: string; age: number } = { name: 'Alice', age: 30 }; // 对象类型
函数参数和返回值类型:在 TypeScript 中,函数参数和返回值也可以有类型注解。
ts
function greet(name: string): string {
return `Hello, ${name}!`;
}
初始化和赋值:变量在使用前必须被初始化,否则 TypeScript 会报错(使用 let 或 const 声明时)。但是,如果变量在使用前只是声明了类型注解而没有赋值,TypeScript 不会报错,因为类型注解只提供了类型信息,并不要求立即赋值。
严格模式:在 TypeScript 的严格模式下(通过配置 tsconfig.json 文件启用),未初始化的变量在使用时会导致编译错误。
var和Let的作用域差异
在JavaScript中,var声明的变量是函数作用域的,而let声明的变量是块级作用域的。TypeScript与之一致。
ts
var a = 6;
大家都能理解,这里定义了一个名为a值为6的变量。但通常,我们很多情况下会把变量定义在函数内部,这就是函数作用域。
ts
function f() {
var message = "Hello, world!";
return message;
}
并且我们也可以在其它函数内部访问相同的变量。
ts
function f() {
var a = 10;
return function g() {
var b = a + 1;
return b;
}
}
var g = f();
g(); // returns 11;
对于熟悉其它语言的人来说,var声明有些奇怪的作用域规则。 看下面的例子:
ts
function f(shouldInitialize: boolean) {
if (shouldInitialize) {
var x = 10;
}
return x;
}
f(true); // returns '10'
f(false); // returns 'undefined'
有些读者可能要多看几遍这个例子。 变量x是定义在if语句里面,但是我们却可以在语句的外面访问它。 这是因为var声明可以在包含它的函数,模块,命名空间或全局作用域内部任何位置被访问(我们后面会详细介绍),包含它的代码块对此没有什么影响。 有些人称此为var作用域或函数作用域。 函数参数也使用函数作用域。
这些作用域规则可能会引发一些错误。 其中之一就是,多次声明同一个变量并不会报错:
ts
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循环会覆盖变量i,因为所有i都引用相同的函数作用域内的变量。 有经验的开发者们很清楚,这些问题可能在代码审查时漏掉,引发无穷的麻烦。
现在你已经知道了var存在一些问题,这恰好说明了为什么用let语句来声明变量。 除了名字不同外,let与var的写法一致。
ts
let hello = "Hello!";
主要的区别不在语法上,而是语义,我们接下来会深入研究。这样一来,我们将构造为块作用域。块作用域的最小单元是一个代码块,用花括号括起来{}。当用let声明一个变量,它使用的是词法作用域或块作用域。 不同于使用var声明的变量那样可以在包含它们的函数外访问,块作用域变量在包含它们的块或for循环之外是不能访问的。
ts
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;
}
块作用域是函数作用域的子集,块作用域的变量只能在块作用域内访问。这样保证了变量安全以及不被污染,也能被及时回收,里我们定义了2个变量a和b。 a的作用域是f函数体内,而b的作用域是if语句块里。 在catch语句里声明的变量也具有同样的作用域规则。
ts
try {
throw "oh no!";
}
catch (e) {
console.log("Oh well.");
}
// Error: 'e' doesn't exist here
console.log(e);
拥有块级作用域的变量的另一个特点是,它们不能在被声明之前读或写。 虽然这些变量始终“存在”于它们的作用域里,但在直到声明它的代码之前的区域都属于暂时性死区。 它只是用来说明我们不能在let语句之前访问它们,幸运的是TypeScript可以告诉我们这些信息。
ts
a++; // illegal to use 'a' before it's declared;
let a;
注意一点,我们仍然可以在一个拥有块作用域变量被声明前获取它。 只是我们不能在变量声明前去调用那个函数。 如果生成代码目标为ES2015,现代的运行时会抛出一个错误;然而,现今TypeScript是不会报错的。
ts
function foo() {
// okay to capture 'a'
return a;
}
// 不能在'a'被声明前调用'foo'
// 运行时应该抛出错误
foo();
let a;
在 JavaScript 中,变量声明(var
、let
、const
)的作用域是函数作用域,而不是块作用域。这意味着,在 JavaScript 中,变量声明的作用域是函数作用域,而不是块作用域。 这是一个暂时性死区,在声明之前,变量不能被引用。为什么会这样,您可以参考这个链接:查看
let和const差异
用以下几点总结,const就是常量
- let声明的变量只在块级作用域内可用,const声明的变量只在块级作用域内可用,const声明的变量的值不能被改变。
- let声明的变量不能在声明之前使用,const声明的变量不能在声明之前使用。
- let声明的变量可以重复声明,const声明的变量不能重复声明。
typescript是如何完成垃圾回收的
TypeScript 本身并不直接处理变量回收,这个任务是委托给 JavaScript 引擎来完成的。TypeScript 是一种静态类型的 JavaScript 超集,它添加了类型系统和对 ES6+ 语法的支持,但在运行时,TypeScript 代码会被编译成纯 JavaScript,然后运行在 JavaScript 引擎(如 V8、SpiderMonkey 等)上。 有关于Javascript的垃圾回收机制,参考这个链接:查看