var与let区别

var声明

 1.作用域规则

  var声明可以在包含它的函数,模块,命名空间或全局作用域内部任何位置被访问,包含它的代码块对此没有什么影响。

  多次声明同一个变量并不会报错。

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

2.变量获取怪异支持

for (var i = 0; i < 10; i++) {
    setTimeout(function() { console.log(i); }, 100 * i);
}

输入结果是:

10 10 10 10 10 10 10 10 10 10

我们期望输出的结果是:0 1 2 3 4 5 6 7 8 9

让我们花点时间考虑在这个上下文里的情况。setTimeout在若干秒后执行一个函数,并且是在for循环结束后。for循环结束后,i的值为10.所以当函数被调用的时候,它会打印出10!通常的解决方法是使用立即执行的函数表达式类捕获每次迭代时i的值。

for (var i = 0; i < 10; i++) {
    // capture the current state of 'i'
    // by invoking a function with its current value
    (function(i) {
        setTimeout(function() { console.log(i); }, 100 * i);
    })(i);
}

let声明

  1.块作用域

    当用lei声明一个变量,它使用的是词法作用域或块作用域。不同于使用var声明的变量那样可以在包含她们的函数外访问,块作用域变量在包含它们的块或for循环之外是不能访问的。

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

    在catch语句里声明的变量也具有相同的作用域规则。

try {
    throw "oh no!";
}
catch (e) {
    console.log("Oh well.");
}

// Error: 'e' doesn't exist here
console.log(e);

    拥有块级作用域的变量的另一个特点是,它们不能在被声明之前读或写。虽然这些变量始终“存在”于它们的作用域里,但在直到声明它的代码之前的区域都属于暂时性死区。她只是用来说明我们不能再let语句之前访问它们。

    注意一点,我们仍然可以在一个拥有块作用域变量被声明前获取它。只是我们不能再变量声明前去调用那个函数。如果生成代码目前为ES2015,现代的运行时会抛出一个错误;然而,现今TypeScript是不会报错的。

    

function foo() {
    // okay to capture 'a'
    return a;
}

// 不能在'a'被声明前调用'foo'
// 运行时应该抛出错误
foo();

let a;

  3.重定义及屏蔽

    var声明时,它不在乎你声明多少次,你只会得到一个。let声明就不会那么宽松了,不能再1个作用域里多次声明相同的变量,(3.1)并不是要求两个均是块级作用域的声明TypeScript才会给出一个错误的警告,(3.2)并不是说块级作用域变量不能用函数作用域变量来声明。而是块级作用域变量需要在明显不同的块里声明。

function f(x) {
    let x = 100; // error: interferes with parameter declaration
}

function g() {
    let x = 100;
    var x = 100; // error: can't have both declarations of 'x'
}
3.1 代码说明
function f(condition, x) {
    if (condition) {
        let x = 100;
        return x;
    }

    return x;
}

f(false, 0); // returns 0
f(true, 0);  // returns 100
3.2代码说明

    在一个嵌套作用域里引入一个新名字的行为称做屏蔽。通常来讲应该避免使用屏蔽,因为我们需要写出清晰的代码。同时也有些场景适合利用它。

function sumMatrix(matrix: number[][]) {
    let sum = 0;
    for (let i = 0; i < matrix.length; i++) {
        var currentRow = matrix[i];
        for (let i = 0; i < currentRow.length; i++) {
            sum += currentRow[i];
        }
    }

    return sum;
}

  4.块级作用域变量的获取

    在我们最初谈及获取用var声明的变量时,我们简略地探究了一下在获取到了变量之后它的行为是怎么样的。直观地讲,每次进入一个作用域时,它创建一个变量的环境。就算作用域内代码已经执行完毕,这个环境与其捕获的变量依然存在。

function theCityThatAlwaysSleeps() {
    let getCity;

    if (true) {
        let city = "Seattle";
        getCity = function() {
            return city;
        }
    }

    return getCity();
}

    当let声明出现在循环体里时拥有完全不同的行为。不仅是在循环里引入了一个新的变量环境,而是针对每次迭代都会创建这样一个新作用域。这就是我们在使用立即执行的函数表达式时做的事。

 

posted @ 2018-01-22 20:32  聆听的风声  阅读(136)  评论(0)    收藏  举报