TypeScript 特性学习摘要

Callback Hell

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

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

[TOC]

一、开发环境
  • 本地

    • 编译环境安装:
    npm install -g typescript
    
    • TypeScript REPL 及执行环境安装:
    npm install -g ts-node
    
  • 在线:TypeScript Playground

二、变量声明及作用域

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
三、字符串新特性
  • 多行字符串,使用反引号 \ 进行引用,解决 JavaScript 中使用\n+` 拼接的麻烦
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)}`);
  • 解决 this 问题(重要)

原来 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 中循环遍历方法的问题:

  • for in:不仅遍历数组中的元素,还会遍历到其他属性
  • forEach:通过回调执行遍历方法,不能通过 break 停止遍历
// 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 的仓库
类型定义文件查找工具

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • 第5章 引用类型(返回首页) 本章内容 使用对象 创建并操作数组 理解基本的JavaScript类型 使用基本类型...
    大学一百阅读 3,219评论 0 4
  • 原文: https://github.com/ecomfe/spec/blob/master/javascript...
    zock阅读 3,371评论 2 36
  • 今天聊天的主题是关于小R,一个有个性的90后小帅哥。 小R身高,用他的话来说就是在一米八的泳池里站着,水面刚过他的...
    Moonlady520阅读 224评论 0 0
  • 你是我心口的一道伤疤, 傻瓜似的不肯离去。 自生自灭的层层代价, 是我不想言说的童话。 总有些故事, 是我与你的恋...
    阿俊xi阅读 350评论 0 3
  • 有一天晚上,wai发盆友圈说:失眠了睡不着啊谁来拯救我呀?评论中有一人秒回:我刚把吹风机放下,你要借不?
    Lea的小期待阅读 214评论 0 0