zoukankan      html  css  js  c++  java
  • TypeScript知识点

    1.1 Typescript 介绍

    1.TypeScript 是由微软开发的一款开源的编程语言,像后端 java、C#这样的面向对象语言可以让 js 开发大型企业项目。

    2.TypeScript 是 Javascript的超级,遵循最新的 ES6、Es5 规范(相当于包含了es6、es5的语法)。TypeScript扩展了JavaScript的语法。

    3.最新的 Vue 、React 也可以集成 TypeScript。

    1.2 Typescript 安装 编译

    安装nodejs环境,用npm全局安装typescript
    npm install -g typescript
    
    Typescript文件后缀名为.ts,最后将编译成js文件

    Typescript手动编译 => tsc + 文件名

    // 将index.ts编译成index.js
    tsc index.ts
    

    1.3 Typescript开发工具Vscode自动编译.ts 文件

    1.3.1 tsc --init 生成配置文件tsconfig.json

    图片描述

    1.3.2 点击菜单栏任务-运行任务(遇到错误使用快捷键ctrl + shift + b),点击 tsc:监视-tsconfig.json 然后就可以自动生成代码

    图片描述

    二、Typescript数据类型

    typescript中为了使编写的代码更规范,更有利于维护,增加了类型校验

    2.1 基础类型

    在typescript中主要给我们提供了以下数据类型:

    布尔类型(boolean) 
    数字类型(number) 
    字符串类型(string) 
    数组类型(array) 
    元组类型(tuple) 
    枚举类型(enum) 
    任意类型(any) 
    null和undefined 
    void类型 
    never类型

    相比于js,typescript中多了枚举类型、任意类型、void类型和never类型

    2.2 变量定义

    写ts代码变量必须指定类型,指定类型后赋值必须为指定的类型,否则报错

    var flag:boolean = true
    flag = 123 // 错误,类型不一致

    2.3 数据类型

    布尔类型(boolean)

    var flag:boolean = true
    
    flag = false // 正确
    
    // flag=123;  // 错误

    数字类型(number)

    var num:number = 123;
    
    num = 456; // 正确 
    
    // num='str';    //错误

    字符串类型(string)

    var str:string = 'this is ts';
    
    str='haha';  //正确
    
    // str=true;  //错误

    数组类型(array) ts中定义数组有两种方式

    // 第一种
    var arr:number[] = [1, 2, 3]
    
    // 第二种
    var arr2:Array<number> = [1, 2, 3]

    元组类型(tuple)元素的类型不必相同,写法和数组一样

    let arr:[number,string] = [123,'this is ts']

    枚举类型(enum)

    用法:

    enum 枚举名{ 
        标识符[=整型常数], 
        标识符[=整型常数], 
        ... 
        标识符[=整型常数], 
    }
    
    enum Flag {success = 1,error = 2};
    
    let s:Flag = Flag.success // 使用枚举类型中的值
    console.log('正确状态',s)
    let f:Flag = Flag.error
    console.log('错误状态',f)

    任意类型(any)

    为那些在编程阶段还不清楚类型的变量指定一个类型

    var number:any = 123
    number = 'str'
    number = true

    2.9 null 和 undefined

    undefined:

    {
        // 在js中,变量已声明但未初始化为undefined
        var undefinedTest:number
        // console.log(undefinedTest) // 错误写法,typescript报错,赋值了才正确
    
        // 在typescript中,已声明未初始化的值要直接访问的话类型需要定义为undefined
        var undefinedTest2:undefined
        console.log(undefinedTest2) // 正确写法,输出undefined 
    }
    {
        // 可能是number类型 可能是undefined
        var undefinedTest3:number | undefined;
        console.log(num);
    }

    null:

    // null是一个空指针对象,undefined是未初始化的变量。因此,可以把undefined看作是空的变量,而null看作是空的对象
    var nullTest:null
    nullTest = null
    // nullTest = {} // 错误,定义了类型是null,值必须为null

    void类型

    typescript中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值。

    // 表示方法没有返回任何类型
    function run(): void {
        console.log('run')
    }
    
    run()

    never类型

    表示的是那些永不存在的值的类型,例如异常
    var a:never
    
    // a = 123 //错误写法
    a = (() => {
        throw new Error('错误');
    })()

    三、Typescript函数

    内容概述: 函数的定义、可选参数、默认参数、剩余参数、函数重载、箭头函数。

    3.1.1 函数的定义

    • es5定义函数有函数声明法和匿名函数法
    // 法一:函数声明法
    
    function run():string {
        return 'run'
    }
    
    /**
    // 错误写法
    function run():string {
        return 123
    }
    */
    
    // 法二:匿名函数
    var run2 = function ():string {
        return 'run2'
    }
    
    console.log('函数定义一', run())
    console.log('函数定义二', run2())

    3.1.2 ts中定义方法传参

    • 函数传参要指定数据类型
    function paramFuc(name:string, age:number):string{
        return `${name} --- ${age}`
    }
    
    console.log('函数传参', paramFuc('dz', 20))

    3.1.3 函数没有返回值的方法用void

    function voidFnc():void{
        console.log('没有返回值的方法用void')
    }
    voidFnc();

    3.2 可选参数

    • es5里面方法的实参和行参可以不一样,但是ts中必须一样,如果不一样就需要在可选参数后加?,这就是可选参数。
    function electParam(name:string, age?:number):string {
        // 这里的age可传可不传,age就是可选参数
        if(age){
            return `${name} --- ${age}`
        }else{
            return `${name} --- 年龄保密`
        }
    }
    console.log('可选参数', electParam('dz'))
    
    // 注意: 可选参数必须配置到参数的最后面
    
    // 错误写法:可选参数不在最后面
    // function electParam2(name?: string, age: number): string {
    //     ...
    // }

    3.3 默认参数

    • es5里面没法设置默认参数,es6和ts中都可以设置默认参数
    // age为默认参数
    function defaultParam(name:string, age:number = 20):String {
        return `${name} --- ${age}`
    }
    
    console.log('默认参数', defaultParam('dz'))

    3.4 剩余参数

    • 当有很多参数时候或参数个数不确定,可以用三点运算符
    // sum参数传过来的是一个数组
    function sum(...result: number[]): number {
        var sum = 0;
    
        for (var i = 0; i < result.length; i++) {
    
            sum += result[i];
        }
    
        return sum;
    }
    console.log('剩余参数', sum(1, 2, 3, 4, 5, 6));
    
    // a=1 b=2 其他参数为剩余参数
    function sum2(a: number, b: number, ...result: number[]): number {
        var sum = a * b;
    
        for (var i = 0; i < result.length; i++) {
    
            sum += result[i];
        }
    
        return sum;
    }
    console.log('剩余参数2', sum2(1, 2, 3, 4, 5, 6));

    3.5 ts函数重载

    同样的函数,传入不同的参数,实现不同的功能
    • java中方法的重载:重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况。
    • typescript中的重载:通过为同一个函数提供多个函数类型定义来实现多种功能的目的。
    • ts为了兼容es5 以及 es6 重载的写法和java中有区别。
    //  es5中同名函数,后面会覆盖前面的函数,ts中则不会 => 函数重载
    function getInfo(name:string):string
    function getInfo(name:string, age:number):string
    function getInfo(name:any, age?:any):any {
        if(age) {
            return '姓名:' + name + '年龄:' + age
        }else{
            return '姓名:' + name
        }
    }
    
    console.log(getInfo('dz'))
    console.log(getInfo('dz', 20))
    // console.log(getInfo(20)) // 错误

    3.6 箭头函数

    箭头函数和es6中一样

    setTimeout(() => {
        console.log('箭头函数')
    }, 1000);

    四、Typescript中的类

    4.1 es5中的类

    内容概述:类的创建、静态方法、继承(对象冒充继承,原型链继承,对象冒充 + 原型链组合继承)

    es5中的面向对象、构造函数、原型与原型链本质可以看这个文档http://caibaojian.com/javascr... , 个人觉得写得很清晰。

    4.1.1 类的创建

    es5类在构造函数和原型链里都可以添加属性和方法,原型链上的属性会被多个实例所共享,而构造函数则不会。

    
    function Person() {
        this.name = 'Ming'
        this.run = function() {
            console.log(this.name + '在运动')
        }
    }
    
    Person.prototype.sex = '男' // 原型链上的属性会被多个实例所共享
    Person.prototype.work = function() {
        console.log(this.name + '在工作')
    }
    
    
    var p = new Person()
    p.run()
    p.work()
    console.log(p.name)
    

    4.1.2 静态方法

    调用静态方法不需要实例化
    
    Person.getInfo=function(){
        console.log('我是静态方法');
    }
    Person.getInfo();
    

    4.1.3 实现继承

    对象冒充(或者叫构造函数继承)继承:可以继承构造函数里面的属性和方法,但是没法继承原型链上面的属性和方法

    原型继承:可以继承构造函数里面的属性和方法,也可以继承原型链上面的属性和方法,但是实例化子类的时候没法给父类传参

    下面是通过对象冒充 + 原型链组合继承,解决了上面两种继承方式存在的问题

    
    function Worker(name,age){
        this.name=name;  /*属性*/
        this.age=age;
        this.run=function(){  /*实例方法*/
            alert(this.name+'在运动');
        }
    
    }      
    Worker.prototype.sex="男";
    Worker.prototype.work=function(){
        alert(this.name+'在工作');
    }
        
    function Web(name,age){
        Worker.call(this,name,age);  // 对象冒充继承,可以继承构造函数里面的属性和方法,实例化子类可以给父类传参
    }
    // Web.prototype = new Worker();  // 原型链继承方法一:继承Worker构造函数和原型上所有的方法和属性
    Web.prototype = Worker.prototype;  //原型链继承方法二:优化了方法一重复继承构造函数属性和方法的问题(本质可以看看http://caibaojian.com/javascript-object-5.html)
    
    var w = new Web('赵四',20);   
    w.run();
    w.work();
    

    从上面可以看出,对象冒充继承是在子类Web构造函数里面通过call方法继承父类Worker的构造函数的属性和方法;原型链继承通过子类Web的原型对象等于父类Worker的原型对象来实现继承;最后这两种继承的组合方式实现了完美继承。

    4.2 typescript中的类

    内容概述: ts中类的定义、继承、类修饰符、静态属性和静态方法、多态、抽象类和抽象方法

    4.2.1 ts中类的定义

    ts中类的定义和es6类的定义一样

    
    class PersonDefine {
        name: string // 属性,前面省略了public关键词
        constructor(name:string) { //构造函数
            this.name = name
        }
        run():string { // 原型
            return `${this.name}在运动`
        }
    }
    var define = new PersonDefine('类的定义')
    alert(define.run())
    

    4.2.2 继承

    ts中继承比es5简单很多,用extends super实现继承
    
    class WebExtend extends PersonDefine {
        constructor(name:string) {
            super(name) // super继承父类的构造函数,并向父类构造函数传参
        }
        work():string {
            return `${this.name}在工作`
        }
    }
    
    var extend = new WebExtend('继承')
    alert(extend.run())
    alert(extend.work())
    

    4.2.3 ts类里面的修饰符

    修饰符:typescript里面定义属性的时候给我们提供了三种修饰符

    • public: 公有修饰符,在当前类里面、子类、类外面都可以访问
    • protected:保护类型,在当前类里面、子类里面可以访问,在类外部没法访问
    • private :私有修饰符,在当前类里面可以访问,子类、类外部都没法访问

    注意:属性如果不加修饰符,默认就是公有修饰符

    
    // 以private为例
    class PersonPrivate{
        private name:string;  /*被private修饰的属性 => 私有属性*/
        constructor(name:string){
            this.name=name;
        }
        run():string{
            return `${this.name}在运动` // 私有属性只能在当前类里面可以访问
        }
    }
    
    class Web extends PersonPrivate{
        constructor(name:string){
            super(name)
        }
        work(){
            // return `${this.name}在工作` // 报错,子类不能访问父类的私有属性
        }
    }
     
    var privateName = new PersonPrivate('private')
    alert(privateName.run())
    // console.log(privateName.name) // 报错,外部不能访问类的私有属性
    

    4.2.4 静态属性和静态方法

    为什么要用静态属性和静态方法?jq里面的$.ajax就是用的静态方法
    
    function $(element) {
        return new Base(element)
    }
    
    function Base(element) {
        this.element = document.getElementById(element)
        this.css = function(arr, value) {
            this.element.style[arr] = value
        }
    }
    $('box').css('color','red')
    $.ajax = function() {}  // 想要在$上使用方法怎么办,用静态方法
    
    ts中实现静态属性和静态方法用static
    
    class PersonStatic{
        /*公有属性*/
        public name:string;
        constructor(name:string) {
            this.name=name;
        }
        /*实例方法(需要被实例化,所以为实例方法)*/
        run(){  
            return `${this.name}在运动`
        }
        /*静态属性*/
        static sex = '男'
        /*静态方法,里面没法直接调用类里面的属性*/
        static info(){  
            // return 'info方法' + this.name  // 静态方法不能调用本类的方法和属性,可以调用静态属性
            return 'info方法' + PersonStatic.sex
        }
    }
    
    console.log('静态方法' + PersonStatic.info())
    console.log('静态属性' + PersonStatic.sex)
    

    4.2.5 多态

    父类定义一个方法不去实现,让继承它的子类去实现,每一个子类的该方法有不同的表现
    • 多态属于继承

    比如定义一个父类Animal,里面的eat方法不去实现,让子类Dog和Cat分别实现自己的eat方法

    
    class Animal {
        name:string;
        constructor(name:string) {
            this.name=name;
        }
        eat(){   // eat方法继承它的子类去实现
        }
    }
    class Dog extends Animal{
        constructor(name:string){
            super(name)
        }
        eat(){
            return this.name+'吃粮食'
        }
    }
    
    class Cat extends Animal{
        constructor(name:string){
            super(name)
        }
        eat(){
            return this.name+'吃老鼠'
        }
    }
    

    4.2.6 抽象类和抽象方法

    定义:用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类(抽象类的子类)中实现
    • 抽象类:它是提供其他类继承的基类,不能直接被实例化,子类继承可以被实例化
    • abstract修饰的方法(抽象方法)只能放在抽象类里面
    • 抽象类和抽象方法用来定义标准(比如定义标准为:抽象类Animal有抽象方法eat,要求它的子类必须包含eat方法)
    
    abstract class AnimalAbst{
        public name:string;
        constructor(name:string){
            this.name=name;
        }
        abstract eat():any;  //抽象方法不包含具体实现并且必须在派生类中实现
        run(){
            console.log('其他方法可以不实现')
        }
    }
    // var a = new Animal() /*错误的写法,抽象类不能被实例化*/
    
    class DogAbst extends Animal{
        //抽象类的子类必须实现抽象类里面的抽象方法
        constructor(name:any){
            super(name)
        }
        eat(){
            return this.name + '吃粮食'
        }
    }
    
    var d = new DogAbst('小花花');
    console.log('抽象类和抽象方法',d.eat());
    

    五、TypesSript接口

    接口定义:接口是对传入参数进行约束;或者对类里面的属性和方法进行声明和约束,实现这个接口的类必须实现该接口里面属性和方法;typescript中的接口用interface关键字定义。

    接口作用:接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。typescrip中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。

    内容概述:接口分类:(属性接口、函数类型接口、可索引接口、类类型接口),接口的继承

    5.1 接口分类

    5.1.1 属性接口

    对传入对象的约束(也就是对json的约束)

    在了解接口之前,我们来看看函数传入obj参数

    
    function printLabel(labelInfo: {label:string}){
        return labelInfo
    }
    // printLabel({name:'obj'});  //错误的写法
    console.log(printLabel({label: 'obj'}))
    

    和上面类似,由此引入属性接口 => 对方法传入参数进行约束

    下面为属性接口的例子,方法printFullName对传入参数FullName(为对象)进行约束

    
    interface FullName{
        firstName: string; // 注意;结束
        secondName: string;
        age?: number // 接口的可选属性用?
    }
    
    function printFullName(name:FullName) {
        // 传入对象必须包含firstName和secondName,可传可不传age
        return name
    }
    var obj = {
        firstName:'小',
        secondName:'明',
        age: 20
    }
    console.log(printFullName(obj))
    

    属性接口应用:原生js封装ajax

    
    interface Config{
        type: string;
        url: string;
        data?: string;
        dataType: string;
    }
    function ajax(config: Config) {
        var xhr = new XMLHttpRequest
        xhr.open(config.type, config.url, true)
        xhr.send(config.data)
        xhr.onreadystatechange = function() {
            if(xhr.readyState == 4 && xhr.status == 200) {
                if(config.dataType == 'json'){
                    console.log(JSON.parse(xhr.responseText))
                }else{
                    console.log(xhr.responseText)
                }
            }
        }
    }
    
    ajax({
        type: 'get',
        data: 'name=xiaoming',
        url: 'http://a.itying.com/api/productlist',
        dataType: 'json'
    })
    

    5.1.2 函数类型接口

    对方法传入的参数以及返回值进行约束
    
    interface encrypt{
        (key: string, value: string): string; // 传入的参数和返回值的类型
    }
    
    var md5:encrypt = function(key:string, value:string):string{
        // encrypt对加密方法md5进行约束,同时md5方法的参数和返回值类型和encrypt要保持一致
        return key + value
    }
    
    console.log(md5('name', '小明'))
    

    5.1.3 可索引接口

    对索引和传入参数的约束(一般用于对数组、对象的约束)

    ts中定义数组:

    
    var arr1:number[] = [1,2]
    var arr2:Array<string> = ['1', '2']
    

    现在用接口来实现:

    
    // 对数组的的约束
    interface UserArr{
        // 索引为number,参数为string
        [index:number]: string
    }
    var userarr:UserArr = ['a', 'b']
    console.log(userarr)
    
    
    // 对象的约束
    interface UserObj{
        // 索引为string,参数为string
        [index:string]: string
    }
    var userobj:UserObj = { name: '小明', sex: '男' }
    console.log(userobj)
    

    5.1.4 类类型接口

    对类的约束,和抽象类抽象有点相似
    
    interface Animal{
        // 对类里面的属性和方法进行约束
        name:string;
        eat(str:string):void;
    }
    // 类实现接口要用implements关键字,必须实现接口里面声明的方法和属性
    class Cat implements Animal{
        name:string;
        constructor(name:string){
            this.name = name
        }
        eat(food:string){
            console.log(this.name + '吃' + food)
        }
    }
    var cat = new Cat('小花')
    cat.eat('老鼠')
    

    5.2 接口的继承

    和类的继承一样,用extends实现接口继承

    下面同时实现类的继承和接口的继承

    
    interface Animal {
        eat(): void;
    }
    // 继承Animal接口,则实现Person接口的类必须也实现Animal接口里面的方法
    interface Person extends Animal {
        work(): void;
    }
    
    class Programmer {
        public name: string;
        constructor(name: string) {
            this.name = name;
        }
        coding(code: string) {
            console.log(this.name + code)
        }
    }
    
    // 继承类并且实现接口
    class Web extends Programmer implements Person {
        constructor(name: string) {
            super(name)
        }
        eat() {
            console.log(this.name + '吃')
        }
        work() {
            console.log(this.name + '工作');
        }
    }
    
    var w = new Web('小李');
    w.eat();
    w.coding('写ts代码');
    

    六、TypesSript泛型

    泛型定义:泛型定义:泛型就是解决类、接口、方法的复用性,以及对不特定数据类型的支持(类型校验)。ts中用T表示泛型。

    泛型公式: <T>表示泛型,调用的时候指定T的数据类型

    软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。

    在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。

    内容概述:内容概述:函数的泛型、类的泛型、泛型接口

    6.1 函数的泛型

    传入的参数类型和返回的参数类型可以指定

    我们来看看函数用ts数据类型,想要同时返回string类型和number类型

    
    function getData1(value:string):string{
        return value;
    }
    function getData2(value:number):number{
        return value;
    }
    

    这样要写不同的函数,不能按照需求返回不同类型数据,造成代码冗余 => 由此引入泛型

    <T>表示泛型,调用的时候指定T的数据类型
    
    function dataT<T>(value:T):T{
        // 传入参数为T 返回值为T
        return value
    }
    dataT<number>(1) // 调用指定泛型为number类型,则传入参数也必须为number类型
    dataT<string>('string')
    
    function dataAny<T>(value:T):any{
        return '传入参数为T,任意类型返回值';
    }
    dataAny<number>(123); // 参数必须是number
    dataAny<string>('这是一个泛型');
    

    6.2 类的泛型

    也是用<T>来实现类的泛型,new的时候指定T的数据类型

    有个最小堆算法,需要同时支持返回数字和字符串两种类型

    使用泛型之前:只能在类的类部指定数据类型,实现需求还要写一套string类型的类

    
    class MinClass{
        public list:number[]=[];
        add(num:number){
            this.list.push(num)
        }
        min():number{
            var minNum=this.list[0];
            for(var i=0;i<this.list.length;i++){
                if(minNum>this.list[i]){
                    minNum=this.list[i];
                }
            }
            return minNum;
        }
    }
    
    var m=new MinClass();
    m.add(1);
    m.add(2);
    alert(m.min());
    

    使用泛型之后:只用一套类来实现

    
    class MinClassT<T>{
        public list:T[]=[];
        add(value:T):void{
            this.list.push(value);
        }
        min():T{        
            var minNum=this.list[0];
            for(var i=0;i<this.list.length;i++){
                if(minNum>this.list[i]){
                    minNum=this.list[i];
                }
            }
            return minNum;
        }
    }
    var m1=new MinClassT<number>();   /*实例化类 并且指定了类的T代表的类型是number*/
    m.add(1);
    m.add(2);
    alert(m1.min())
    
    var m2=new MinClassT<string>();   /*实例化类 并且指定了类的T代表的类型是string*/
    m2.add('c');
    m2.add('a');
    alert(m2.min())
    

    6.3 泛型接口

    有一个函数类型接口

    
    interface ConfigFn{
        (value:string):string;
    }
    var setData:ConfigFn = function(value:string):string{
        return value
    }
    setData('name');
    // setData(20); // 错误
    

    setData(20);写法错误,想要传入number类型的参数又要写一个函数类型接口 => 用泛型接口

    泛型接口有两种写法:

    
    // 泛型接口定义方式一
    interface ConfigFnOne{
        <T>(value:T):T;
    }
    var setDataOne:ConfigFnOne = function<T>(value:T):T{
        return value
    }
    // 既可以传入string也可以传入number类型参数
    setDataOne<string>('name');
    setDataOne<number>(20);
    
    
    // 泛型接口定义方式二
    interface ConfigFnTwo<T>{
        (value:T):T;
    }
    function setDataTwo<T>(value:T):T{
        return value
    }
    var setDataTwoFn:ConfigFnTwo<string> = setDataTwo
    setDataTwoFn('name');
    

    示例代码请查看github,欢迎start https://github.com/dzfrontend...

  • 相关阅读:
    Python 爬虫入门(一)
    Dubbo、Zookeeper集群搭建及Rose使用心得(二)
    Dubbo、Zookeeper集群搭建及Rose使用心得(一)
    JAVA 加密算法初探DES&AES
    Android 蓝牙模块基础操作
    IntelliJ IDEA 使用随笔
    Maven+SSM框架实现简单的增删改查
    记录一次bug解决过程:数据迁移
    SSM框架+Plupload实现断点续传(Spring+SpringMVC+MyBatis+Plupload)
    JAVA开发环境
  • 原文地址:https://www.cnblogs.com/zhuxinpeng-looking/p/11334986.html
Copyright © 2011-2022 走看看