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

function f(condition, x) { if (condition) { let x = 100; return x; } return x; } f(false, 0); // returns 0 f(true, 0); // returns 100
在一个嵌套作用域里引入一个新名字的行为称做屏蔽。通常来讲应该避免使用屏蔽,因为我们需要写出清晰的代码。同时也有些场景适合利用它。
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声明出现在循环体里时拥有完全不同的行为。不仅是在循环里引入了一个新的变量环境,而是针对每次迭代都会创建这样一个新作用域。这就是我们在使用立即执行的函数表达式时做的事。