从var声明提及
一直以来我们都是经由过程var关键字定义JavaScript变量。
var a = 10;
var声明的变量var声明能够在包括它的函数,模块,定名空间或全局作用域内部任何位置被接见。
比方在别的函数内部接见雷同的变量:
function f() {
var a = 10;
return function g() {
var b = a + 1;
return b;
}
}
var g = f();
g(); // returns 11;
这些作用域划定规矩可能会激发一些毛病。
- 第1个题目就是屡次声明同一个变量并不会报错。比方下面这个例子:
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;
}
sumMatrix([[1,2],[3,4]])
平常以为,运转的效果应该为10。但效果并非如此,由于一切i都援用雷同的函数作用域内的变量,里层的for轮回会掩盖变量i,所以如今的效果是3而不是10。所以运用var声明时,它不在意你声明多少次你只会获得1个。
- setTimeout中的非常
看下面这段代码:
for (var i = 0; i < 10; i++) {
setTimeout(function() { console.log(i); }, 100 * i);
}
我们希冀的效果是:每隔100*i毫秒打印出1个数字,递次为1-10,但现实打印出的全部都是10。这是由于setTimeout在多少毫秒后实行一个函数,而且是在for轮回完毕后。 for轮回完毕后,i的值为10。 所以当函数被挪用的时刻,它会打印出 10!我们不能不应用一个马上实行函数处理这个题目:
for(var i = 0; i < 10; i++){
(function(i){setTimeout(()=>console.log(i), i * 100);})(i)
}
var声明的变量带给我们这么多搅扰,所以在typescript中加入了let对变量举行声明。
let声明
let与var的写法一致:
let hello = "Hello!";
let声明的变量和var声明的变量有许多差别之处,let处理了var变量带来的搅扰。
- 块作用域
当用let声明一个变量,它运用的是块作用域。 差别于运用 var声明的变量那样能够在包括它们的函数外接见,块作用域变量在包括它们的块或for轮回以外是不能接见的。
function f(input: boolean) {
let a = 100;
if (input) {
let b = a + 1;
return b;
}
return b;
}
在上面代码中,a能够在if语句中被接见,由于a在函数语句中声明,在if语句以外,而b就不能在if语句块以外被接见,由于b是在if语句块中被声明的。
在catch语句里声明的变量也具有一样的作用域划定规矩。
try {
throw "oh no!";
}
catch (e) {
console.log("Oh well.");
}
console.log(e); //error
在catch语句块外,e是不能被接见的。
在let语句声明之前接见let声明的变量,效果为undefined。
function foo() {
// okay to capture 'a'
return a;
}
console.log(foo()); //
let a = 10;
- 重定义及屏障
var声明时,不管你声明多少次,你只会获得1个。
var x = 10;
console.log(x); //10
var x = 20;
console.log(x); //20
let声明,须要遵照块作用域划定规矩,在一个块作用域中反复声明变量会发生毛病提醒,另一个用var声明也不允许。
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;
}
console.log(f(true, 0)); //100
console.log(f(false, 0)); //0
在一个嵌套作用域里引入一个新名字的行动称做屏障。 它是一把双刃剑,它可能会不小心肠引入新题目,同时也可能会处理一些毛病。 比方,假定我们如今用 let重写之前的sumMatrix函数。
function sumMatrix(matrix: number[][]){
let sum = 0;
for(let i = 0; i < matrix.length; i++){
let current = matrix[i];
for(let i = 0; i < current.length; i++){
sum += current[i];
}
}
return sum;
}
console.log(sumMatrix([[1,2],[3,4]])); //10
此次能够获得准确的效果10,由于内层轮回中的i屏障了外层轮回中的i。但这类写法是不引荐的。
- 块级作用域变量的猎取
function theCityThatAlwaysSleeps() {
let getCity;
if (true) {
let city = "Seattle";
getCity = function() {
return city;
}
}
return getCity();
}
上面这段代码能够一般实行。由于我们已经在city的环境里猎取到了city,所以就算if语句实行完毕后我们依然能够接见它。
当let声明出如今轮回体里时具有完整差别的行动,针对每次迭代都邑建立一个新作用域。所以在 setTimeout例子里我们仅运用let声明就能够了。
for(let i = 0; i < 10; i ++){
setTimeout(()=>console.log(i), i*100);
}
会输出与预感一致的效果:1 2 3 4 5 6 7 8 9
const 声明
const 声明是声明变量的另一种体式格局。它们与let声明类似,然则就像它的名字所表达的,它们被赋值后不能再转变。
const numLivesForCat = 9;
它们具有与 let雷同的作用域划定规矩,然则不能对它们从新赋值。
const kitty = {
name: "Aurora",
numLives: numLivesForCat,
}
// Error
kitty = {
name: "Danielle",
numLives: numLivesForCat
};
但const变量内部的状况照样能够转变的。
const kitty = {
name: "Aurora",
numLives: numLivesForCat,
}
// all "okay"
kitty.name = "Rory";
kitty.name = "Kitty";
kitty.name = "Cat";
kitty.numLives--;
let与const的区分
末了,说说let与const的区分,援用官网的发起:
运用最小特权准绳,一切变量除了你计划去修正的都应该运用const。 基本准绳就是假如一个变量不须要对它写入,那末别的运用这些代码的人也不能够写入它们,而且要思索为何会须要对这些变量从新赋值。 运用 const也能够让我们更轻易的推想数据的活动。