变量声明

var

首先,我们来看一个例子

  1. for(var i = 0;i<10;i++){
  2. setTimeout(function(){
  3. console.log(i);
  4. },1000);
  5. };
  6. // 10 10 10 ... 10

有经验的读者或者直接运行代码后,我们知道控制台在1s后会输出10次同样的数字10;这明显与我们想要的从0开始依次输出到9不一致。 如果我们想要依然用var来声明i并想得到所要的结果,就要像下面这样做:

  1. for(var i = 0;i<10;i++){
  2. (function(i){
  3. setTimeout(function(){
  4. console.log(i);
  5. },1000);
  6. })(i);
  7. };
  8. // 0 1 2 3 ... 9

可以看出上面为了实现想要的效果,用到了立即执行函数(IIFE)。 用到立即执行函数,解决的其实就是函数作用域的问题。

为了解决var声明的变量的作用域问题,ES6的创建了letconst两个工具来声明变量。而typescript同样支持这两个声明的工具

let

同样的我们来看一个例子: ```javascript var a = 1; var a = 10; console.log(a); // 10

let b = 1; let b = 11; console.log(b); // 报错

  1. > 同样声明同一个变量,var声明多次,后面的声明会覆盖前面声明;而let重复声明同一个变量则会报错。
  2. > 第二个例子:
  3. > ```javascript
  4. function foo() {
  5. console.log(a)
  6. }
  7. foo();
  8. var a = 10;
  9. // undefined
function foo() {
    console.log(a)
}
// 不能在'a'被声明前调用'foo'
// 运行时应该抛出错误
foo();
let a = 10;
// a is not defined

造成这样的结果是变量在foo()函数执行之后声明,但又因为var声明的变量会有变量提升,即会先把var声明的变量a提升到函数执行的顶部,但此时并没有赋值,所以foo函数里面读取到的只是声明了的a,还没有被赋值,所以是undefined; 而let声明的变量并没有变量提升,在foo()执行的时候函数体内的a被没有被声明,所以会报错a is not defined

let声明的变量除了不能被重复声明和没有变量提升的特点外,还拥有两个跟var声明的变量一样的特点:可被重复赋值(不是重复被声明)和拥有块级作用域。 所谓块级作用域:即let声明的变量所在的区域被称作块,这个变量会被“锁住”在所在的区域内(块内),这个被声明的变量都可以被访问到,而在区域之外(块外)就不能被访问到。 如:

function foo() {
    var a = 10;
}
console.log(a);
// 10
// 块级作用域
function foo() {
    let a = 10;
}
console.log(a);
// 报错信息:a is not defined
// 重复赋值
function foo() {
    let a = 10;
    a = 100;
    console.log(a);
};
foo();
// 100

const

constlet的加强型声明变量的工具,除了拥有let一样的块级作用域外,被加强的地方在于const 声明的变量不能被重复赋值,其他功能跟let一样。

const a = 10;
function test(flag){
    if(flag){
        a = 11;
    }
    console.log(a);
};
test(true);
// 报错信息:Assignment to constant variable.
// ############################
let a = 10;
function test(flag){
    if(flag){
        a = 11;
    }
    console.log(a);
};
test(true);
// 11