• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

Typescript学习(一)

武飞扬头像
langzitianya
帮助1

以下内容基于对TypeScript Deep Dive的学习。

目录

为什么使用TypeScript

代码风格

JavaScript

  判断相等

  引用

  Null vs. Undefined

  this

  闭包(Closure)

  Number类型

  Truthy

现在使用未来JavaScript的功能

  类

    使用类

    继承(Inheritance)

    静态成员(Statics)

    访问修饰符(Access Modifiers)

    Abstract修饰符

    构造方法

  箭头函数/Lambda函数

  可变个数参数

  let

  const

  解构

  展开运算符

  for...of

  Iterator

  模板文字

  Promise

    Promise链

    创建Promise

    并行处理

    将回调函数转换为Promise

  生成器

    生成器函数可用于创建惰性迭代器

    外部控制执行

  async await


为什么使用TypeScript

  为JavaScript提供可选类型系统
    类型可以提高重构时的开发速度。通过有类型,在写代码的时候可以注意到错误,立即修复错误。
    默认设置下,编译时即使有类型错误也会生成JavaScript代码。
  将JavaScript未来版本中计划的功能用于当前(非现代)JavaScript环境
    TypeScript使旧的JavaScript(ES5之前)运行环境也能使用ES6以后版本中计划的很多功能。TypeScript团队正在积极添加功能。

  隐式推断类型

  1.  
    var foo = 123; // 推断为number类型
  2.  
    foo = '456'; // 错误: 无法将'string'代入'number'

  明确指定类型

  1.  
    var foo: number = 123;
  2.  
    var foo: number = '123'; // 错误: 无法将'string'代入'number'

  结构类型

  1.  
    interface Point2D {
  2.  
    x: number;
  3.  
    y: number;
  4.  
    }
  5.  
    interface Point3D {
  6.  
    x: number;
  7.  
    y: number;
  8.  
    z: number;
  9.  
    }
  10.  
    var point2D: Point2D = { x: 0, y: 10 }
  11.  
    var point3D: Point3D = { x: 0, y: 10, z: 20 }
  12.  
    function iTakePoint2D(point: Point2D) { /* 其他处理 */ }
  13.  
     
  14.  
    iTakePoint2D(point2D); // 相同结构没问题
  15.  
    iTakePoint2D(point3D); // 多了属性也没问题
  16.  
    iTakePoint2D({ x: 0 }); // 错误:'y'不存在
学新通

使用既存JavaScript库的时候,可以使用declare声明消除编译时类型错误

  1.  
    $('.awesome').show(); // 错误:'$'不存在
  2.  
     
  3.  
    declare var $: any;
  4.  
    $('.awesome').show(); // 不报错了
  5.  
     
  6.  
    declare var $: { (selector: string): any };
  7.  
    $('.awesome').show(); // 不报错了
  8.  
    $(123).show(); // 错误: selector必须是string类型

代码风格

  变量名、函数名、类成员和方法名、接口成员名、类型成员名 都使用小驼峰命名法,比如:camelCase
  类名、接口名、类型名、命名空间、枚举类型和成员名 都使用大驼峰命名法,比如:PascalCase
  接口名不加'I'前缀

  null vs. undefined

    推荐别使用null和undefined来声明不可用

  1.  
    // Bad
  2.  
    let foo = { x: 123, y: undefined };
  3.  
    // Good
  4.  
    let foo: { x: number, y?: number } = { x: 123 };

    通常使用undefined

  1.  
    // Bad
  2.  
    return null;
  3.  
    // Good
  4.  
    return undefined;

    如果是API或传统API的一部分,则使用null

  1.  
    // Bad
  2.  
    cb(undefined)
  3.  
    // Good
  4.  
    cb(null)

    使用truthy检查对象是null或undefined

  1.  
    // Bad
  2.  
    if (error === null)
  3.  
    // Good
  4.  
    if (error)

    使用== null / != null (不使用 === / !==)来检查null/undefined,因为同时适用于null和undefined,但不适用与其他假值(如:'',0,false)

  1.  
    // Bad
  2.  
    if (error !== null) // 只排除null,不排除undefined
  3.  
    // Good
  4.  
    if (error != null) // 同时排除null和undefined

  使用代码格式化
  引号
    除非需要转义,否则建议使用单引号(')
    如果不能使用双引号,请尝试使用反引号(`)

  缩进使用2空格,不是TAB
  语句后使用分号
  声明数组使用foos: Foo[]而不使用foos: Array<Foo>
  文件名使用小驼峰命名,比如:accordion.tsx、myControl.tsx、utils.ts

  type vs interface

    需要UNION型或交叉型时使用type

      type Foo = number | { someProperty: number }

    想做extend和implements的时候使用interface

  1.  
    interface Foo {
  2.  
    foo: string;
  3.  
    }
  4.  
    interface FooBar extends Foo {
  5.  
    bar: string;
  6.  
    }
  7.  
    class X implements FooBar {
  8.  
    foo: string;
  9.  
    bar: string;
  10.  
    }

  == or ===

    这两个都对TypeScript用户来说几乎是安全的。推荐使用TypeScript代码库中使用的===

JavaScript

  判断相等

    JavaScript需要注意的一点是==和===的不同,==会尝试在两个变量之间进行类型强制转换。
    例如在以下情况下,字符串将转换为数字。

  1.  
    console.log(5 == "5"); // JavaScript:true , TypeScript会报错
  2.  
    console.log(5 === "5"); // JavaScript:false , TypeScript会报错
  3.  
    console.log("" == "0"); // JavaScript:false , TypeScript:false
  4.  
    console.log(0 == ""); // JavaScript:true , TypeScript会报错

    与==和===一样,!=和!==会做同样的处理
    所以,除了检查null以外,都建议使用===和!==


    不能用于比较结构类型的内容

  1.  
    console.log({a:123} == {a:123}); // False
  2.  
    console.log({a:123} === {a:123}); // False

    可以使用deep-equal npm包进行结构类型的比较

  1.  
    import * as deepEqual from "deep-equal";
  2.  
    console.log(deepEqual({a:123},{a:123})); // True

  引用

    除了文字(字符串、数字、boolean等)之外,JavaScript中的任何对象(包括函数、数组、正则表达式等)都是引用。
    修改会影响所有引用的值

  1.  
    var foo = {};
  2.  
    var bar = foo; // bar是同一个对象的引用
  3.  
    foo.baz = 123;
  4.  
    console.log(bar.baz); // 123

    等号比较也是比较的引用

  1.  
    var foo = {};
  2.  
    var bar = foo; // bar是foo的引用
  3.  
    var baz = {}; // baz是另一个对象
  4.  
    console.log(foo === bar); // true
  5.  
    console.log(foo === baz); // false

  Null vs. Undefined

    JavaScript(以及扩展的TypeScript)有两种底层类型:null和undefined。它们的意思是不同的:
      内容尚未初始化:undefined
      内容当前不可用:null

    判断

  1.  
    console.log(undefined == undefined); // true
  2.  
    console.log(null == undefined); // true
  3.  
    console.log(0 == undefined); // false
  4.  
    console.log('' == undefined); // false
  5.  
    console.log(false == undefined); // false

      推荐使用== null / != null (不使用 === / !==)来检查null/undefined,因为同时适用于null和undefined,但不适用与其他假值(如:'',0,false)
      一般情况下不需要区分是null还是undefined


    全局级别变量未定义的判断

  1.  
    if (typeof someglobal !== 'undefined') {
  2.  
    console.log(someglobal);
  3.  
    }

    限制显式使用undefined

      {a:1,b:undefined} 应该改成 {a:1}

    Node形式的回调

      Node形式的回调函数里,没有发生错误的时候,err对象一般设定为null,开发者使用truthy检查

  1.  
    fs.readFile('someFile', 'utf8', (err,data) => {
  2.  
    if (err) {
  3.  
    // 错误处理
  4.  
    } else {
  5.  
    // 正常处理
  6.  
    }
  7.  
    });

      在创建自己的API时,为了保持一致性,在这种情况下可以使用null。
      出于对自己API的诚意,您应该考虑promise,在这种情况下,您实际上不需要为缺少的错误值而烦恼(您使用.then与.catch来处理它们)。

    不要使用undefined表示无效值

  1.  
    // Bad
  2.  
    function toInt(str:string) {
  3.  
    return str ? parseInt(str) : undefined;
  4.  
    }
  5.  
    // Good
  6.  
    function toInt(str: string): { valid: boolean, int?: number } {
  7.  
    const int = parseInt(str);
  8.  
    if (isNaN(int)) {
  9.  
    return { valid: false };
  10.  
    }
  11.  
    else {
  12.  
    return { valid: true, int };
  13.  
    }
  14.  
    }

    JSON和序列化
      JSON标准支持null的编码,不支持undefined

        JSON.stringify({willStay: null, willBeGone: undefined}); // {"willStay":null}

  this

    函数中对this的访问取决于函数是如何调用的。这通常被称为调用上下文。

  1.  
    function foo() {
  2.  
    console.log(this);
  3.  
    }
  4.  
    foo(); // 全局调用,日志输出为window对象
  5.  
    let bar = {
  6.  
    foo
  7.  
    }
  8.  
    bar.foo(); // 在bar上调用,日志输出为bar对象

  闭包(Closure)

    JavaScript中的函数可以访问外部范围中定义的任何变量。

  1.  
    function outerFunction(arg) {
  2.  
    var variableInOuterFunction = arg;
  3.  
    function bar() {
  4.  
    console.log(variableInOuterFunction); // 访问外部范围中定义的变量
  5.  
    }
  6.  
    // 调用本地函数以证明它可以访问arg
  7.  
    bar();
  8.  
    }
  9.  
    outerFunction("hello closure"); // 日志输出:"hello closure"

    即使在外部函数返回之后,内部函数也可以从外部范围访问变量。这是因为变量仍然绑定在内部函数中,而不依赖于外部函数。

  1.  
    function outerFunction(arg) {
  2.  
    var variableInOuterFunction = arg;
  3.  
    return function() {
  4.  
    console.log(variableInOuterFunction);
  5.  
    }
  6.  
    }
  7.  
    var innerFunction = outerFunction("hello closure!");
  8.  
    // 注意outerFunction已经返回
  9.  
    innerFunction(); // 日志输出:"hello closure!"

    它允许轻松地组合对象,例如揭示模块模式(Revealing module pattern):

  1.  
    function createCounter() {
  2.  
    let val = 0;
  3.  
    return {
  4.  
    increment() { val },
  5.  
    getVal() { return val }
  6.  
    }
  7.  
    }
  8.  
    let counter = createCounter();
  9.  
    counter.increment();
  10.  
    console.log(counter.getVal()); // 1
  11.  
    counter.increment();
  12.  
    console.log(counter.getVal()); // 2

  Number类型

    核心类型
      JavaScript只有一种数字类型。它是一个双精度64位数字。

    10进制数(Decimal)
      如果你是精通其他语言中double/float的人,你会知道二进制浮点与十进制小数对应不正确。

        console.log(.1   .2); // 0.30000000000000004

    整数(Integer)
      整数值的界限是由内置的Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER决定。

  1.  
            console.log({max: Number.MAX_SAFE_INTEGER, min: Number.MIN_SAFE_INTEGER});
  2.  
            // {max: 9007199254740991, min: -9007199254740991}

      在这种情况下,安全是指该值不能是舍入误差的结果。
      不安全的值与这些安全值相差 1/-1,任何数量的加法/减法都将使结果舍入。

  1.  
    console.log(Number.MAX_SAFE_INTEGER 1 === Number.MAX_SAFE_INTEGER 2); // true!
  2.  
    console.log(Number.MIN_SAFE_INTEGER - 1 === Number.MIN_SAFE_INTEGER - 2); // true!
  3.  
    console.log(Number.MAX_SAFE_INTEGER); // 9007199254740991
  4.  
    console.log(Number.MAX_SAFE_INTEGER 1); // 9007199254740992 - Correct
  5.  
    console.log(Number.MAX_SAFE_INTEGER 2); // 9007199254740992 - Rounded!
  6.  
    console.log(Number.MAX_SAFE_INTEGER 3); // 9007199254740994 - Rounded - correct by luck
  7.  
    console.log(Number.MAX_SAFE_INTEGER 4); // 9007199254740996 - Rounded!

      要检查安全性,请使用ES6的Number.isSafeInteger:

  1.  
    console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER)); // true
  2.  
    console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER 1)); // false
  3.  
    console.log(Number.isSafeInteger(Number.MAX_SAFE_INTEGER 10)); // false

    big.js

      财务计算(例如GST计算、带美分的货币、加法等)时,都要使用big.js这样的库
        完美十进制数学
        安全的越界整数值

  1.  
    npm install big.js @types/big.js
  2.  
     
  3.  
    import { Big } from 'big.js';
  4.  
    export const foo = new Big('111.11111111111111111111');
  5.  
    export const bar = foo.plus(new Big('0.00000000000000000001'));
  6.  
    // 获取数字
  7.  
    const x: number = Number(bar.toString()); // 失去精度

    NaN

      如果数字计算不能用有效数字表示,JavaScript将返回一个特殊的NaN值。

        console.log(Math.sqrt(-1)); // NaN

      不能用等号判断NaN,需要使用Number.isNaN

  1.  
    // Bad
  2.  
    console.log(NaN === NaN); // false!!
  3.  
    // Good
  4.  
    console.log(Number.isNaN(NaN)); // true

    无穷大(Infinity)

      Number可以表示的界限值为Number.MAX_VALUE和-Number.MAX_VALUE

  1.  
    console.log(Number.MAX_VALUE); // 1.7976931348623157e 308
  2.  
    console.log(-Number.MAX_VALUE); // -1.7976931348623157e 308

      精度未更改的超出范围的值受这些限制。

  1.  
    console.log(Number.MAX_VALUE 1 == Number.MAX_VALUE); // true!
  2.  
    console.log(-Number.MAX_VALUE - 1 == -Number.MAX_VALUE); // true!

      精度更改范围之外的值将解析为特殊值Infinity/-Infinity。

  1.  
    console.log(Number.MAX_VALUE 10**1000); // Infinity
  2.  
    console.log(-Number.MAX_VALUE - 10**1000); // -Infinity

      除以0也是无穷大

  1.  
    console.log( 1 / 0); // Infinity
  2.  
    console.log(-1 / 0); // -Infinity

      可以手动使用这些Infinity值,也可以使用Number类的静态成员

  1.  
    console.log(Number.POSITIVE_INFINITY === Infinity); // true
  2.  
    console.log(Number.NEGATIVE_INFINITY === -Infinity); // true

      幸运的是,比较运算符(</>)可以起作用

  1.  
    console.log( Infinity > 1); // true
  2.  
    console.log(-Infinity < -1); // true

    无穷小(Infinitesimal)

      Number可以表示的非0最小值为Number.MIN_VALUE

        console.log(Number.MIN_VALUE);  // 5e-324

      小于Number.MIN_VALUE的值就直接变0了

        console.log(Number.MIN_VALUE / 10);  // 0

  Truthy

    真假判断

变量类型 判定为False的值 判定为True的值
boolean false true
string ''(空字符串) 其他字符串
number 0/NaN 其他数字
null 一直是false  
undefined 一直是false  
其他对象(包含{}[])   一直是true

    使用!!可以强制转换成boolean类型,原理是两次取非运算

  1.  
    let name = 'abc';
  2.  
    const hasName = !!name; // hasName的值为true

现在使用未来JavaScript的功能

  TypeScript的主要卖点之一是,它允许您在当前的(ES3和ES5级别)JavaScript引擎(如当前的浏览器和Node.js)中使用ES6及更高版本的一系列功能。

  类

    使用类

      类提供了一个有用的结构抽象
      为开发人员提供了一种一致的方式来使用类,而不是使用每个框架(emberjs、reactjs等)来开发自己的版本。
      面向对象开发人员已经了解了类。

  1.  
    class Point {
  2.  
    x: number;
  3.  
    y: number;
  4.  
    constructor(x: number, y: number) {
  5.  
    this.x = x;
  6.  
    this.y = y;
  7.  
    }
  8.  
    add(point: Point) {
  9.  
    return new Point(this.x point.x, this.y point.y);
  10.  
    }
  11.  
    }
  12.  
    var p1 = new Point(0, 10);
  13.  
    var p2 = new Point(10, 20);
  14.  
    var p3 = p1.add(p2); // {x:10,y:30}

    继承(Inheritance)

      TypeScript中的类支持使用extends关键字单一继承
      父类构造函数使用super调用,父类方法使用super.方法名调用

  1.  
    class Point3D extends Point {
  2.  
    z: number;
  3.  
    constructor(x: number, y: number, z: number) {
  4.  
    super(x, y);
  5.  
    this.z = z;
  6.  
    }
  7.  
    add(point: Point3D) {
  8.  
    var point2D = super.add(point);
  9.  
    return new Point3D(point2D.x, point2D.y, this.z point.z);
  10.  
    }
  11.  
    }

    静态成员(Statics)

      TypeScript类支持类的所有实例共享的static属性。放置和访问静态成员的自然位置是类本身。

  1.  
    class Something {
  2.  
    static instances = 0;
  3.  
    constructor() {
  4.  
    Something.instances ;
  5.  
    }
  6.  
    }
  7.  
     
  8.  
    var s1 = new Something();
  9.  
    var s2 = new Something();
  10.  
    console.log(Something.instances); // 2

    访问修饰符(Access Modifiers)

      使用不同修饰符的属性或方法的可访问性:

可以访问的地方 public protected private
类(class) yes yes yes
子类(class children) yes yes no
类的实例(class instances) yes no no

      未指定时默认为public

    Abstract修饰符

      抽象可以被认为是一个访问修饰符。我们将其单独呈现,因为与前面提到的修饰符不同,它可以在类上,也可以在类的任何成员上。
      具有抽象修饰符主要意味着不能直接调用此类功能,并且必须由子类提供该功能。
      抽象类不能直接实列化,抽象方法不能直接使用,必须在子类中实现后才能使用。

    构造方法

      构造方法不是必须的
      构造方法的参数前可以加访问修饰符,对应的变量会自动在类内定义,可以在其他地方直接使用

  1.  
    class Foo {
  2.  
    constructor(public x:number) {
  3.  
    }
  4.  
    }

      可以在构造方法外进行变量初始化

  1.  
    class Foo {
  2.  
    members = []; // 无构造函数直接初始化成员变量
  3.  
    add(x) {
  4.  
    this.members.push(x);
  5.  
    }
  6.  
    }

  箭头函数/Lambda函数

    与函数型语言相比,JavaScript有必须频繁输入function的倾向。使用箭头函数可以简单地创建函数

      var inc = (x)=>x 1;

    箭头函数中的this代表周围上下文,不会因为调用者不同发生改变

  1.  
    function Person(age) {
  2.  
    this.age = age;
  3.  
    this.growOld = () => {
  4.  
    this.age ;
  5.  
    }
  6.  
    }
  7.  
    var person = new Person(1);
  8.  
    setTimeout(person.growOld,1000);
  9.  
    // 输出为2,如果不使用箭头函数输出为1
  10.  
    setTimeout(function() { console.log(person.age); },2000);

    箭头函数的必要性
      除了能得到简洁的语法之外,如果想让其他的东西调用函数的话,只要使用箭头函数就可以了。

  1.  
    var growOld = person.growOld;
  2.  
    // Then later someone else calls it:
  3.  
    growOld();

    箭头函数可以继承
      子类中使用this调用父类中的箭头函数

  1.  
    子类中使用this调用父类中的箭头函数
  2.  
    class Adder {
  3.  
    constructor(public a: number) {}
  4.  
    add = (b: number): number => {
  5.  
    return this.a b;
  6.  
    }
  7.  
    }
  8.  
    class Child extends Adder {
  9.  
    callAdd(b: number) {
  10.  
    return this.add(b);
  11.  
    }
  12.  
    }
  13.  
    // Demo to show it works
  14.  
    const child = new Child(123);
  15.  
    console.log(child.callAdd(123)); // 246
学新通

    返回单一对象的箭头函数

  1.  
    var foo = () => ({
  2.  
    bar: 123
  3.  
    });

  可变个数参数

    参数个数不固定,剩余的参数会以数组的形式接收

  1.  
    function iTakeItAll(first, second, ...allOthers) {
  2.  
    console.log(allOthers);
  3.  
    }
  4.  
    iTakeItAll('foo', 'bar'); // []
  5.  
    iTakeItAll('foo', 'bar', 'bas', 'qux'); // ['bas','qux']

  let

    JavaScript中的var定义的变量作用域为函数内
    let定义的变量作用域为块内

  1.  
    var foo = 123;
  2.  
    if (true) {
  3.  
    var foo = 456;
  4.  
    }
  5.  
    console.log(foo); // 456
  6.  
    let foo = 123;
  7.  
    if (true) {
  8.  
    // 生成JS时发现重名会自动改名
  9.  
    let foo = 456;
  10.  
    }
  11.  
    console.log(foo); // 123

    闭包时let使用的是变量的当时值,var使用最终值

  1.  
    var funcs = [];
  2.  
    for (var i = 0; i < 3; i ) {
  3.  
    funcs.push(function() {
  4.  
    console.log(i);
  5.  
    })
  6.  
    }
  7.  
    for (var j = 0; j < 3; j ) {
  8.  
    // 输出全部为3
  9.  
    funcs[j]();
  10.  
    }
  11.  
    var funcs = [];
  12.  
    for (let i = 0; i < 3; i ) { // 这里使用的let
  13.  
    funcs.push(function() {
  14.  
    console.log(i);
  15.  
    })
  16.  
    }
  17.  
    for (var j = 0; j < 3; j ) {
  18.  
    // 输出为0,1,2
  19.  
    funcs[j]();
  20.  
    }
学新通

  const

    const是ES6/TypeScript提供的一个非常受欢迎的添加。它允许您对变量保持不变。从文档和运行时的角度来看,这都很好。

      const foo = 123;

    const声明常量时必须同时初始化,之后值不能改变
    如果保存的是对象,对象的引用不能变,但是对象内的值可以变

  1.  
    const foo = { bar: 123 };
  2.  
    foo = { bar: 456 }; // 报错
  3.  
    foo.bar = 456; // 允许

    const的作用域与let一致,都是块内

  1.  
    const foo = 123;
  2.  
    if (true) {
  3.  
    const foo = 456; // 允许定义块内使用的另一个foo
  4.  
    }

  解构

    可以使用解构取出对象的部分属性或者数组的部分值
    对象的解构

  1.  
    var rect = { x: 0, y: 10, width: 15, height: 20 };
  2.  
    var {x, y, width, height} = rect;
  3.  
    console.log(x, y, width, height); // 0,10,15,20
  4.  
     
  5.  
    rect.x = 10;
  6.  
    ({x, y, width, height} = rect); // 使用外括号分配给现有变量
  7.  
    console.log(x, y, width, height); // 10,10,15,20

      要将展开的变量分配给新变量名,请执行以下操作:

  1.  
    const obj = {"some property": "some value"};
  2.  
    const {"some property": someProperty} = obj;
  3.  
    console.log(someProperty === "some value"); // true

      也可以使用解构获取结构的深层数据

  1.  
    var foo = { bar: { bas: 123 } };
  2.  
    var {bar: {bas}} = foo; // 相当于: `var bas = foo.bar.bas;`

    对象解构中使用Rest

      可以拆出指定项目以外的其他项目作为一个单独的对象

  1.  
    var {w, x, ...remaining} = {w: 1, x: 2, y: 3, z: 4};
  2.  
    console.log(w, x, remaining); // 1, 2, {y:3,z:4}

    数组的解构

  1.  
    var x = 1, y = 2;
  2.  
    [x, y] = [y, x];
  3.  
    console.log(x, y); // 2,1

    数组解构中使用Rest

      可以拆出指定下标以外的其他项目作为一个单独的数组

  1.  
    var [x, y, ...remaining] = [1, 2, 3, 4];
  2.  
    console.log(x, y, remaining); // 1, 2, [3,4]

      可以跳过不需要的下标

  1.  
    var [x, , ...remaining] = [1, 2, 3, 4];
  2.  
    console.log(x, remaining); // 1, [3,4]

  展开运算符

    把对象或数组的元素平铺展开
      展开运算符是一种很好的语法,可以让JavaScript中常用的apply的this参数不必传递难以理解的null
      另外,通过使用分割数组或代入其他数组的语法,可以用简单的代码对部分数组进行处理

    对象的展开
      展开时如果有同名,后面的值会覆盖前面的值

  1.  
    const point2D = {x: 1, y: 2};
  2.  
    const anotherPoint3D = {x: 5, z: 4, ...point2D};
  3.  
    console.log(anotherPoint3D); // {x: 1, y: 2, z: 4}
  4.  
    const yetAnotherPoint3D = {...point2D, x: 5, z: 4}
  5.  
    console.log(yetAnotherPoint3D); // {x: 5, y: 2, z: 4}
  6.  
    const foo = {a: 1, b: 2, c: 0};
  7.  
    const bar = {c: 1, d: 2};
  8.  
    const fooBar = {...foo, ...bar}; // `fooBar`: {a: 1, b: 2, c: 1, d: 2}

    数组的带入

  1.  
    var list = [1, 2];
  2.  
    list = [...list, 3, 4];
  3.  
    console.log(list); // [1,2,3,4]

      可以展开到任意位置

  1.  
    var list = [1, 2];
  2.  
    list = [0, ...list, 4];
  3.  
    console.log(list); // [0,1,2,4]

  for...of

    数组循环

  1.  
    var someArray = [9, 2, 5];
  2.  
    for (var item of someArray) {
  3.  
    console.log(item); // 9,2,5
  4.  
    }

    可以把字符串拆成字符

  1.  
    var hello = "is it me you're looking for?";
  2.  
    for (var char of hello) {
  3.  
    console.log(char); // is it me you're looking for?
  4.  
    }

    限制
      如果您的目标不是ES6或更高版本,则生成的代码假设对象上存在属性长度,并且可以通过数字(例如obj[2])对对象进行索引。因此,对于这些遗留的JS引擎,它只在字符串和数组上受支持。
      如果TypeScript可以看到你没有使用数组或字符串,它会给你一个明确的错误“不是数组类型或字符串类型”。

  Iterator

    它本身不是TypeScript或ES6的功能,而是面向对象编程语言中常见的“行为设计模式”。这通常是实现以下接口的对象:

  1.  
    interface Iterator<T> {
  2.  
    next(value?: any): IteratorResult<T>;
  3.  
    return?(value?: any): IteratorResult<T>;
  4.  
    throw?(e?: any): IteratorResult<T>;
  5.  
    }
  6.  
    interface IteratorResult<T> {
  7.  
    done: boolean;
  8.  
    value: T;
  9.  
    }

    如果只实现Iterator接口,可以使用next方法遍历
    如果只使用[Symbol.iterator]符号,可以使用for...of,但不能使用next方法遍历
    如果实现TypeScript的IterableIterator接口,可以同时使用next方法和for...of

  1.  
    class Frame implements IterableIterator<Component> {
  2.  
    private pointer = 0;
  3.  
    constructor(public name: string, public components: Component[]) {}
  4.  
     
  5.  
    public next(): IteratorResult<Component> {
  6.  
    if (this.pointer < this.components.length) {
  7.  
    return {
  8.  
    done: false,
  9.  
    value: this.components[this.pointer ]
  10.  
    }
  11.  
    } else {
  12.  
    return {
  13.  
    done: true,
  14.  
    value: null
  15.  
    }
  16.  
    }
  17.  
    }
  18.  
     
  19.  
    [Symbol.iterator](): IterableIterator<Component> {
  20.  
    return this;
  21.  
    }
  22.  
     
  23.  
    }
学新通

    迭代器不仅可以单纯返回元素,还可以用于递归计算,比如计算Fibonacci数列

  1.  
    class Fib implements IterableIterator<number> {
  2.  
    protected fn1 = 0;
  3.  
    protected fn2 = 1;
  4.  
    constructor(protected maxValue?: number) {}
  5.  
     
  6.  
    public next(): IteratorResult<number> {
  7.  
    var current = this.fn1;
  8.  
    this.fn1 = this.fn2;
  9.  
    this.fn2 = current this.fn1;
  10.  
    if (this.maxValue != null && current >= this.maxValue) {
  11.  
    return {
  12.  
    done: true,
  13.  
    value: null
  14.  
    }
  15.  
    }
  16.  
    return {
  17.  
    done: false,
  18.  
    value: current
  19.  
    }
  20.  
    }
  21.  
    [Symbol.iterator](): IterableIterator<number> {
  22.  
    return this;
  23.  
    }
  24.  
    }
  25.  
    let fib = new Fib();
  26.  
     
  27.  
    fib.next() //{ done: false, value: 0 }
  28.  
    fib.next() //{ done: false, value: 1 }
  29.  
    fib.next() //{ done: false, value: 1 }
  30.  
    fib.next() //{ done: false, value: 2 }
  31.  
    fib.next() //{ done: false, value: 3 }
  32.  
    fib.next() //{ done: false, value: 5 }
  33.  
     
  34.  
    let fibMax50 = new Fib(50);
  35.  
    console.log(Array.from(fibMax50)); // [ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34 ]
  36.  
     
  37.  
    let fibMax21 = new Fib(21);
  38.  
    for(let num of fibMax21) {
  39.  
    console.log(num); //Prints fibonacci sequence 0 to 21
  40.  
    }
学新通

  模板文字

    在语法上,字符串使用反引号(`)代替单引号(')或双引号(“)。

    字符串展开(String Interpolation)
      ${}中间可以是变量或表达式,最后生成的字符串会把实际的值进行代入

  1.  
    var lyrics = 'Never gonna give you up';
  2.  
    var html = `<div>${lyrics}</div>`;
  3.  
    console.log(`1 and 1 make ${1 1}`);

    多行文字

  1.  
    var lyrics = `Never gonna give you up
  2.  
    Never gonna let you down`;

    标记的模板

      您可以在模板字符串之前放置一个函数(称为标记),这样它就有机会预处理模板字符串文字加上所有占位符表达式的值,并返回结果。
      所有静态文字都作为第一个参数的数组传入。占位符表达式的所有值都作为剩余的参数传入。最常见的情况是,您只需要使用rest参数将这些参数转换为数组。

  1.  
    var say = "a bird in hand > two in the bush";
  2.  
    var html = htmlEscape `<div> I would just like to say : ${say}</div>`;
  3.  
     
  4.  
    // 您可以将占位符声明为任意类型的数组。TypeScript都会键入check,以确保用于调用标记的占位符与注释匹配。
  5.  
    // 例如,如果你希望处理字符串或数字:...placeholders:(string | number)[]
  6.  
    function htmlEscape(literals: TemplateStringsArray, ...placeholders: string[]) {
  7.  
    let result = "";
  8.  
     
  9.  
    // 将文字与占位符交错
  10.  
    for (let i = 0; i < placeholders.length; i ) {
  11.  
    result = literals[i];
  12.  
    result = placeholders[i]
  13.  
    .replace(/&/g, '&amp;')
  14.  
    .replace(/"/g, '&quot;')
  15.  
    .replace(/'/g, '&#39;')
  16.  
    .replace(/</g, '&lt;')
  17.  
    .replace(/>/g, '&gt;');
  18.  
    }
  19.  
     
  20.  
    // 追加最后的文字
  21.  
    result = literals[literals.length - 1];
  22.  
    return result;
  23.  
    }
学新通

  Promise

    Promise类存在于许多时髦的JavaScript引擎中,可以轻松地polyfill。想使用Promise的理由是,对于异步/回调风格的代码,可以使用同步处理的写法处理错误。


    Promise链

      Promise的链条是使用Promise的最大优点。一旦取得Promise,从那个时候开始,可以使用then函数制作Promise的链。
      如果您从链中的任何函数返回promise,那么只有在解析值后才会调用.then:

  1.  
    Promise.resolve(123)
  2.  
    .then((res) => {
  3.  
    console.log(res); // 123
  4.  
    return 456;
  5.  
    })
  6.  
    .then((res) => {
  7.  
    console.log(res); // 456
  8.  
    return Promise.resolve(123); // 返回resolve的Promise
  9.  
    })
  10.  
    .then((res) => {
  11.  
    console.log(res); // 123 : 使用resolve的值调用后面的.then
  12.  
    return 123;
  13.  
    })

      可以将链前面部分的错误处理聚合为单个catch

  1.  
    Promise.reject(new Error('something bad happened'))
  2.  
    .then((res) => {
  3.  
    console.log(res); // 不会调用
  4.  
    return 456;
  5.  
    })
  6.  
    .then((res) => {
  7.  
    console.log(res); // 不会调用
  8.  
    return 123;
  9.  
    })
  10.  
    .catch((err) => {
  11.  
    console.log(err.message); // something bad happened
  12.  
    });

      catch实际上返回一个新的promise(有效地创建了一个新promise链):

  1.  
    Promise.reject(new Error('something bad happened'))
  2.  
    .then((res) => {
  3.  
    console.log(res); // 不会调用
  4.  
    return 456;
  5.  
    })
  6.  
    .catch((err) => {
  7.  
    console.log(err.message); // something bad happened
  8.  
    return 123;
  9.  
    })
  10.  
    .then((res) => {
  11.  
    console.log(res); // 123
  12.  
    })

      在then(或catch)中抛出的任何同步错误都会导致返回的promise失败:

  1.  
    Promise.resolve(123)
  2.  
    .then((res) => {
  3.  
    throw new Error('something bad happened'); // 抛出同步错误
  4.  
    return 456;
  5.  
    })
  6.  
    .then((res) => {
  7.  
    console.log(res); // 不会调用
  8.  
    return Promise.resolve(789);
  9.  
    })
  10.  
    .catch((err) => {
  11.  
    console.log(err.message); // something bad happened
  12.  
    })

      对于给定的错误,只调用相关的(最近的尾部)catch(因为catch启动了一个新的promise链)。

  1.  
    Promise.resolve(123)
  2.  
    .then((res) => {
  3.  
    throw new Error('something bad happened'); // 抛出同步错误
  4.  
    return 456;
  5.  
    })
  6.  
    .catch((err) => {
  7.  
    console.log('first catch: ' err.message); // something bad happened
  8.  
    return 123;
  9.  
    })
  10.  
    .then((res) => {
  11.  
    console.log(res); // 123
  12.  
    return Promise.resolve(789);
  13.  
    })
  14.  
    .catch((err) => {
  15.  
    console.log('second catch: ' err.message); // 不会调用
  16.  
    })
学新通

      只有在前一个链中出现错误时才会调用catch:

  1.  
    Promise.resolve(123)
  2.  
    .then((res) => {
  3.  
    return 456;
  4.  
    })
  5.  
    .catch((err) => {
  6.  
    console.log("HERE"); // 不会调用
  7.  
    })

    创建Promise

  1.  
    import fs = require('fs');
  2.  
    function readFileAsync(filename: string): Promise<any> {
  3.  
    return new Promise((resolve,reject) => {
  4.  
    fs.readFile(filename,(err,result) => {
  5.  
    if (err) reject(err);
  6.  
    else resolve(result);
  7.  
    });
  8.  
    });
  9.  
    }

    并行处理

      Promise提供了一个静态Promise.all函数,您可以使用它来等待n个Promise完成,全部完成后才执行then。

  1.  
    let item1, item2;
  2.  
    Promise.all([loadItem(1), loadItem(2)])
  3.  
    .then((res) => { // 响应内容为数组,与all里的Promise对应
  4.  
    [item1, item2] = res;
  5.  
    console.log('done');
  6.  
    });

      Promise提供了一个静态Promise.race函数,可以在多个Promise中的任意一个完成时就返回。

  1.  
    Promise.race([task1, task2]).then(function(value) {
  2.  
    console.log(value); // "one"
  3.  
    // 响应内容为最早完成的Promise任务的返回值
  4.  
    });

    将回调函数转换为Promise

  1.  
    const delay = (ms: number) => new Promise(res => setTimeout(res, ms));
  2.  
    delay(1000)
  3.  
    .then(() => {
  4.  
    })

  生成器

    function *是用于创建生成器函数的语法。调用生成器函数将返回生成器对象。生成器对象遵循迭代器接口(即next、return和throw函数)。


    生成器函数可用于创建惰性迭代器

  1.  
    function* idMaker(){
  2.  
    let index = 0;
  3.  
    while(index < 3)
  4.  
    yield index ;
  5.  
    }
  6.  
     
  7.  
    let gen = idMaker();
  8.  
    console.log(gen.next()); // { value: 0, done: false }
  9.  
    console.log(gen.next()); // { value: 1, done: false }
  10.  
    console.log(gen.next()); // { value: 2, done: false }
  11.  
    console.log(gen.next()); // { done: true }

    外部控制执行

      本质上,函数可以暂停其执行,并将剩余函数执行的控制(命运)传递给调用方。

  1.  
    function* generator(){
  2.  
    console.log('Execution started');
  3.  
    yield 0;
  4.  
    console.log('Execution resumed');
  5.  
    yield 1;
  6.  
    console.log('Execution resumed');
  7.  
    }
  8.  
     
  9.  
    var iterator = generator();
  10.  
    console.log('Starting iteration'); // 它在生成器函数的主体之前运行
  11.  
    console.log(iterator.next()); // { value: 0, done: false }
  12.  
    console.log(iterator.next()); // { value: 1, done: false }
  13.  
    console.log(iterator.next()); // { value: undefined, done: true }

      当为生成器对象调用next时,函数只执行一次
      函数在yield语句出现时立即暂停
      函数在next被调用时重新启动

      yield暂停生成器函数的通信,允许将控制传递到函数外部
      可以从外部向生成器函数主体发送值
      从外部,可以对生成器函数主体抛出异常

  1.  
    function* generator() {
  2.  
    var bar = yield 'foo'; // bar可以是any类型
  3.  
    console.log(bar); // bar!
  4.  
    }
  5.  
     
  6.  
    const iterator = generator();
  7.  
    // 开始执行,直到我们获得第一个输入值
  8.  
    const foo = iterator.next();
  9.  
    console.log(foo.value); // foo
  10.  
    // 传入'bar'再执行
  11.  
    const nextThing = iterator.next('bar');
  12.  
     
  13.  
    function* generator() {
  14.  
    try {
  15.  
    yield 'foo';
  16.  
    } catch(err) {
  17.  
    console.log(err.message); // bar!
  18.  
    }
  19.  
    }
  20.  
     
  21.  
    var iterator = generator();
  22.  
    // 开始执行,直到我们获得第一个输入值
  23.  
    var foo = iterator.next();
  24.  
    console.log(foo.value); // foo
  25.  
    // 继续执行抛出异常
  26.  
    var nextThing = iterator.throw(new Error('bar'));
学新通

  async await

    如果Promise使用了await关键字,则暂停执行JavaScript代码。然后,仅当从该函数返回的Promise完成时,代码才重新开始执行。
      如果Promise成功,await返回响应内容
      如果Promise失败,抛出可以同步处理的异常

  1.  
    async function foo() {
  2.  
    try {
  3.  
    var val = await getMeAPromise();
  4.  
    console.log(val);
  5.  
    } catch(err) {
  6.  
    console.log('Error: ', err.message);
  7.  
    }
  8.  
    }

    在异步函数的开头使用async关键字,async函数总是返回Promise

  1.  
    function delay(milliseconds: number, count: number): Promise<number> {
  2.  
    return new Promise<number>(resolve => {
  3.  
    setTimeout(() => {
  4.  
    resolve(count);
  5.  
    }, milliseconds);
  6.  
    });
  7.  
    }
  8.  
    async function dramaticWelcome(): Promise<void> {
  9.  
    console.log("Hello");
  10.  
     
  11.  
    for (let i = 0; i < 5; i ) {
  12.  
    const count:number = await delay(500, i);
  13.  
    console.log(count);
  14.  
    }
  15.  
     
  16.  
    console.log("World!");
  17.  
    }
  18.  
     
  19.  
    dramaticWelcome();
学新通

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhihbfej
系列文章
更多 icon
同类精品
更多 icon
继续加载