资讯专栏INFORMATION COLUMN

TypeScript学习笔记—变量的声明

BingqiChen / 813人阅读

摘要:声明的变量声明可以在包含它的函数,模块,命名空间或全局作用域内部任何位置被访问。但是块级作用域变量需要在明显不同的块里声明。会输出与预料一致的结果声明声明是声明变量的另一种方式。

从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也可以让我们更容易的推测数据的流动。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/93494.html

相关文章

  • typeScript学习笔记

    摘要:联合类型,指赋值的时候可以是联合类型中的某一个。任意属性允许创建对象的时候,定义接口中没有的属性。常见的类型推论,还提现在函数表达式中。 typeScript是什么? TypeScript 是 JavaScript 的一个超集,主要提供了类型系统和对 ES6 的支持 安装typeScript npm install -g typeScript 安装完成查看版本: tsc -v typ...

    Guakin_Huang 评论0 收藏0
  • TypeScript学习笔记—安装与基础类型

    摘要:的基础类型为了让程序有价值,我们需要能够处理最简单的数据单元数字,字符串,结构体,布尔值等。支持与几乎相同的数据类型,此外还提供了实用的枚举类型方便我们使用。枚举类型是对标准数据类型的一个补充。使用枚举类型可以为一组数值赋予友好的名字。 angular等大型框架的基础语言为typescript,学习了一阵angular后,又回来重新学习typescript,有了一些体会,在这里和大家进...

    quietin 评论0 收藏0
  • TypeScript入门-声明与结构、函数

    摘要:声明和结构在中,支持和这样的声明方式。解构就是将声明的一组变量与相同结构的数组或者对象的元素数值一一对应,并将变量相对应元素进行赋值。 学习Angular 2 , 《揭秘Angular 2》读书笔记。Angular2 选择 TypeScript 作为其官方最主要的构建语音,这意味着掌握 TypeScript 语音将更有利于高效地开发 Angular 应用。 声明和结构 在TypeScr...

    CoyPan 评论0 收藏0
  • 【译】使用TypeScript两年后-值得吗?

    摘要:弄了一个持续更新的笔记,可以去看看,链接地址此篇文章的地址使用两年后值得吗基础笔记的地址可以也可以。使用,你可以使用抽象类等功能。有关抽象类的更多信息支持,和方法,只读属性。 弄了一个持续更新的github笔记,可以去看看,链接地址:Front-End-Basics 此篇文章的地址:使用TypeScript两年后-值得吗? 基础笔记的github地址:https://githu...

    RyanQ 评论0 收藏0
  • 初入typescript笔记

    摘要:注意变量声明没有指定类型。因此,程序使用类型推断来确定变量的数据类型,第一次赋值为,设置为类型。 typescript 的基本类型1.number 数字类型 example: let val: Number = 22.string 字符串 example: let val: String = 23.Boolean 布尔类型 example: let val: Boolean = fal...

    fsmStudy 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<