TypeScript我爱编程

TypeScript 特性学习摘要

2017-01-15  本文已影响0人  舌尖上的大胖

Callback Hell

首先,向我的偶像 Anders Hejlsberg 致敬!
本文是根据 慕课网TypeScript入门 的视频教程整理的摘要,详情请访问原作视频。
完整信息参见官方文档 TypeScript Documentation
源码:TypeScript 在 GitHub 的仓库

【目的】
本文档目的是让熟悉 JavaScript 的同学快速了解 TypeScript 特色,准确信息请务必参考所使用版本 TypeScript 对应的官方文档。

[TOC]

一、开发环境
二、变量声明及作用域

TypeScript可以使用兼容JavaScript的var声明方式,也可以使用letlet解决了JavaScript臭名昭著的作用域问题。代码如下:

// TypeScript,使用 var 声明变量,不支持块级作用域
var n = 1;
{
    var n = 200;
    console.log('块级变量 n 值:' + n);
}
console.log('全局变量 n 值:' + n);

被编译成的 JavaScript,与上面的 TypeScript 一样:

// 使用 var 定义变量的 TypeScript 编译成的 JavaScript
var n = 1;
{
    var n = 200;
    console.log('块级变量 n 值:' + n);
}
console.log('全局变量 n 值:' + n);

期待的执行结果为:

块级变量 n 值:200
全局变量 n 值:1

实际执行结果为:

块级变量 n 值:200
全局变量 n 值:200

如果使用 TypeScript 的 let 声明变量:

// TypeScript,使用 let 声明变量,不支持块级作用域
let n = 1;
{
    let n = 200;
    console.log('块级变量 n 值:' + n);
}
console.log('全局变量 n 值:' + n);

被编译成的 JavaScript:

// 使用 let 定义变量的 TypeScript 编译成的 JavaScript
var n = 1;
{
    var n_1 = 200;
    console.log('块级变量 n 值:' + n_1);
}
console.log('全局变量 n 值:' + n);

发现编译器为块内变量重新命名,执行结果符合预期:

块级变量 n 值:200
全局变量 n 值:1
三、字符串新特性
var str = `line 1
line 2
...
line n`;
var content = 'abc';
console.log(`<div>
${content}
</div>`);

调用时,自动将字符串中的表达式值作为参数传入函数

function myTest(template, param1, param2) {
    console.log(template);
    console.log(param1);
    console.log(param2);
}

myTest`测试字符串分割,传入参数 ${111} and ${222} ,再看结果`

从执行结果看,template 是一个数组,这个数组是被字符串中的几个表达式给分割成段的结果。

四、函数
function testParam(sUserName: string, nUserAge: number): string {
    var ret = `User name: ${sUserName}
User age: ${nUserAge}`;
    return ret;
}

var s: string = testParam('bahb', 2);
console.log(s);

带有默认值的参数,必须放在参数列表最后

function testArgumentDefaultValue(arg1, arg2, arg3 = 'arg 3 default value') {
    console.log(arg1);
    console.log(arg2);
    console.log(arg3);
    console.log('===============');
}
testArgumentDefaultValue('1', '2', '3');
testArgumentDefaultValue('5', '6');
function func(...args) {
    args.forEach(function (e) {
        console.log(e);
    });
    console.log('--------------');
}

func(1, 2, 3);
func(4, 5, 6, 7, 8);
五、析构表达式

用于将对象、数组中的元素,拆分到变量中。

var {aa, bb} = {
    aa: 11,
    bb: 22
}

console.log(aa);
console.log(bb);
var {aa: aa_alias, bb: bb_alias, cc:{v2}} = {
    aa: 11,
    bb: 22,
    cc: {
        v1: 333,
        v2: 444
    }
}

console.log(aa_alias);
console.log(bb_alias);
console.log(v2);

数组,通过直接写逗号 , 来空过元素,通过 ...参数 的形式,读取剩余元素形成数组。

var [n1, n2, , ...others] = [1, 2, 3, 4, 5];
console.log(n1);
console.log(n2);
//注意通过逗号空过了第三个元素
console.log(others);
六、箭头表达式

箭头表达式 主要用于:

  1. 作为匿名函数使用
  2. 解决匿名函数中的 this 问题
var myFunc = arg1 => console.log(arg1);
myFunc('aaa');
var myFunc = (arg1, arg2) => arg1 + arg2;
console.log(myFunc(111, 222));
var myFunc = (arg1, arg2) => {
    var sum = arg1 + arg2;
    console.log(sum);
    return sum;
}
console.log(`exec result: ${myFunc(111, 222)}`);

原来 JavaScript 的书写方式:

var MyClass = function (name) {
    this.name = name;
    this.counter = 0;
    setInterval(function () {
        this.counter++;
        console.log(this.name + this.counter);
    }, 1000);
}

var obj = new MyClass('bahb_');

期待每间隔1秒,陆续输出bahb_1、bahb_2...,实际上没有取到值。
原因是由于通过 new 之后,this 的指代发生了变化,导致取不到值。
直接把 MyClass 作为函数调用,

MyClass('bahb_');

倒是可以得到正常的结果,原因是函数作为顶级对象,this 的指代不会变,但是这种形式不能满足需要创建对象的场景。

通过箭头表达式来解决问题:

var MyClass = function (name) {
    this.name = name;
    this.counter = 0;
    setInterval(() => {
        this.counter++;
        console.log(this.name + this.counter);
    }, 1000);
}

var obj = new MyClass('bahb_');
七、循环遍历集合

JavaScript 中循环遍历方法的问题:

// TypeScript 的 for of 循环
let arr = [1, 2, 3, 4];
arr.desc = 'abc'; // 使用 for of,属性不会被遍历到
for (let x of arr) {
    console.log(x);
}
八、泛型(Generic)

这里只举例说明下基本概念,实际泛型的应用场景会广泛得多。

let myArr: Array<string> = [];
myArr.push('aa');
myArr.push('bb');
myArr.push(123); // 数据类型不一致,报错
console.log(myArr);

抄个官方的 Demo 吓吓人:

class Greeter<T> {
    greeting: T;
    constructor(message: T) {
        this.greeting = message;
    }
    greet() {
        return this.greeting;
    }
}

let greeter = new Greeter<string>("Hello, world");

let button = document.createElement('button');
button.textContent = "Say Hello";
button.onclick = function() {
    alert(greeter.greet());
}

document.body.appendChild(button);
九、面向对象
1、类定义、继承、访问权限控制符
class Animal {
    // 构造函数,当构造函数传入的参数加上了“访问权限控制符”,则同时会声明同名类属性,并赋值
    constructor(public name: string) { }
    protected log(arg) {
        console.log(arg);
    }
    move(distanceInMeters: number = 0) {
        this.log(`${this.name} moved ${distanceInMeters}m.`);
        this.log('==============');
    }
}

class Snake extends Animal {
    constructor(name: string) {
        // 调用父类构造器
        super(name);
    }
    move(distanceInMeters = 5) {
        this.log("Slithering...");
        // 通过 super 调用父类方法
        super.move(distanceInMeters);
    }
}

class Horse extends Animal {
    constructor(name: string) { super(name); }
    move(distanceInMeters = 45) {
        this.log("Galloping...");
        super.move(distanceInMeters);
    }
}

let sam = new Snake("Sammy the Python");
let tom: Animal = new Horse("Tommy the Palomino");

sam.move();
tom.move(34);
2、接口

实现类必须实现接口中声明的每个方法

interface IPerson {
    eat();
    work();
}

class Person implements IPerson {
    eat() { }; // 不实现该方法会报错
    work() { }; // 不实现该方法会报错
}
十、模块(Module)

每个 .ts 文件就是一个模块,通过 export 来对外部模块暴露元素,通过 import 来引入模块。
举例:utility.ts 输出,main.ts 引用 utility.ts 中的输出

// Module Utility: utility.ts

let str: string = 'abc';

function add(arg1, arg2) {
    return arg1 + arg2;
}

class MyClass {
    doSth() { }
}

export {str};
export {add};
export {MyClass};
// Module Main: main.ts

import {add} from "./utility";

let ret = add(2, 3);
console.log(ret);

或者


// Module Main: main.ts

import * as myUtility from "./utility";

let ret = myUtility.add(2, 3);
console.log(ret);
十一、注解(Annotation)

给框架或IDE用的说明,比如:使用某个类时应该同时引入哪些页面等等,需要时具体看手册即可。

十二、类型定义文件(*.d.ts)

类型定义文件 用于描述一个库中所定义的类型
类型定义文件介绍
类型定义文件使用

类型定义文件从这里找:DefinitelyTyped

DefinitelyTyped - The repository for high quality TypeScript type definitions
或者访问 DefinitelyTyped 在 GitHub 的仓库
类型定义文件查找工具
上一篇下一篇

猜你喜欢

热点阅读