TypeScript 是 JavaScript 的超集,同 JavaScript 一样,声明变量可以采用下面三个关键字:
var
1、不存在块级作用域
在 ES6 之前,ECMAScript 的作用域只有两种:
- 全局作用域
- 函数作用域
/*
这里的 i 是在全局作用域中的,只存在一个值。
setTimeout 这个异步函数在若干毫秒后执行,
并且它是在 for 循环结束后的。在 for 循环结束后,
i 的值为 10,所以当函数被调用的时候,它会打印出 10。
*/
for (var i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i)
}, 100 * i)
}
//如果期望输出的结果是: 0,1,2,3,4,5,6,7,8,9
1、创建函数作用域:
for (var i = 0; i < 10; i++) {
f(i)
}
function f(i) {
setTimeout(function () {
console.log(i)
}, 100)
}
或者
for (var i = 0; i < 10; i++) {
(function (i) {
setTimeout(function () {
console.log(i)
}, 100 * i)
})(i)
}
2、通过
let关键字创建块级作用域:for (let i = 0; i < 10; i++) {
setTimeout(function () {
console.log(i)
}, 100 * i)
}
通过块级声明的变量无法被代码块外部访问,这种就称为块级作用域,也成为语法作用域
块级作用域可以在函数内部和代码块{}内部创建
2、存在变量提升
console.log(a) // undefined
var a = 1
// 等价于var a
console.log(a) // undefined
a = 1
// 如果将var变为let/const,会报错a is not defined未定义,这里也可以看出var与let在变量提升的不同:
- var 会将变量的创建和初始化都进行提升
- let 只会将创建提升,而初始化未被提升,称之为暂时性死区
let
1、let和const不存在变量提升(不可以声明提前),原因let和const之前的区域叫做暂存性死区,var的变量存在变量提升
2、使用let和const声明的变量不再属于window,不能通过window.变量名 无法访问,var声明的变量属于window
3、使用块级作用域不能在同一级中重复声明变量(let变量不能重复声明)
新增了“块级作用域”,定义在代码块中的变量在代码块被执行结束后会被释放掉:
{
var a = 10;
// 变量b只能在代码块内访问
let b = 20;
console.log(b)//20
}
console.log(a)//10
console.log(b)// b is not defined
/* 第 3 - 4 行,a 变量在 if{} 代码块中是有效的,正常输出 10。第7行,在 if{} 代码块外就被释放掉了,所以会报错误。包括在一对花括号中的一组语句称之为”代码块“,它可以替换掉
*/
function block() {
if (true) {
let a = 10
console.log(a) // 10
}console.log(a) // Cannot find name 'a'.ts(2304)
}
4、重定义
var x
var x
var x
这是一个完全有效的代码,所有 x 的声明其实都指向了同一个引用,但这也是很多 bug 产生的原因。 let 的声明就严格了许多:
let x
let x // Cannot redeclare block-scoped variable 'x'
const
1、const和let除了const声明的是常量,其他和let一样
2、关键字 const 声明变量,它被赋值后不能再改变,即是不能重新赋值。用 const 声明变量,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动。用 const 声明初始数据类型如布尔值、数字、字符串,可以理解为声明常量。因为这些初始类型的值就保存在变量所指向的那个内存地址。
const num = 10
const brand = 'imooc'
const registered = true
num = 20 // Cannot assign to 'num' because it is a constant.ts(2588)
对于复合类型的数据来说,变量所指向的内存地址保存的只是一个指针,const 能够保证其指针不变,但属性值是可变的:
const person = {
name: 'Tom',
address: 'Baker Street 221b'
}
// error
person = {
name: 'Sherlock',
address: 'Baker Street 221b'
}
// ok
person.name = 'Sherlock'
3、注意:必须在const声明常量的时候就赋值
小结
阅读本小节中三种不同的变量声明,我们知道了:
let和count实现了块级作用域。- 所有变量除了你计划去修改的都应该使用
const。 - 尽量使用
let和const来声明变量,减少var的使用。