typeScript学习记录 (下)

作者: 小枫枫

临枫的项目经历分享给你们啦~

扫码交朋友

标签:

特别声明:文章有少部分为网络转载,资源使用一般不提供任何帮助,特殊资源除外,如有侵权请联系!

接着上章的写  点我直达上一章

 

ts类中定义静态属性 / 静态方法 /抽象类 / 多态

我们先来回顾一下ES5中定义静态属性和静态类

function People6(){
}

People.doHomework = function(){
    console.log("临枫正在做作业");
}
People.whatAreYouDoing = '做作业'
People.doHomework(); //输出 临枫正在做作业
console.log(People.whatAreYouDoing);//输出 :做作业
 
在ts中定义静态方法
class People7{
    public name:string;
    static name2:string = "小枫枫";
    constructor(name:string){
        this.name = name;
    }
    work(){
        console.log(this.name + '在上班')
    }
    write(){
        console.log(this.name + '在写作业')
    }
    // 静态方法的关键字  static
    static reading(){
        console.log("小枫枫正在读《typeScript从精通到陌生》")
    }
    static buybuybuy(){
        console.log(this.name+"正在买买买")
    }

    static buybuybuy2(){
        console.log(this.name2+"618正在买买买")
    }
}
// 静态方法  不需要new实例 直接调用
People7.reading();//打印:小枫枫正在读《typeScript从精通到陌生》

People7.buybuybuy(); //打印 People7正在买买买    --->  静态方法里面无法调用类里面的属性 

// 如果需要使用 需要定义静态属性  属性前面加关键字 static

People7.buybuybuy2(); //小枫枫618正在买买买

 

ts中的继承多态
多态:父类定义一个方法不去实现,让继承他的子类去实现 ,每个子类有不同的表现 

class People8{
    name:string;
    constructor(name:string){
        this.name = name;
    }
    duWhat(){
        // 做什么?  不知道啊  具体谁在干吗   继承他的子类去实现  子类重写父类方法 每个子类的表现不一样
        console.log("在干嘛")
    }
}
class linfeng3 extends People8{
    constructor(name:string){
        super(name);
    }
    duWhat(){
        console.log(this.name + "正在学习")
    }
}
let lf8 = new linfeng3("临枫");
// lf8.duWhat();//输出:临枫正在学习

class chaoran extends People8{
    constructor(name:string){
        super(name);
    }
    duWhat(){
        console.log(this.name + "在种地")
    }
}
let cr = new chaoran("大眼");
// cr.duWhat();//输出:大眼在种地
 
 ts中的抽象类
 
// ts中的抽象类,它是提供其他类继承的基类,不能直接被实例化      用来定义一个标准
// 用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
// abstract 抽象方法只能放在抽象类中


abstract class People9{
    name:string;
    constructor(name:string){
        this.name = name;
    }
    abstract write():string
}
// 抽象方法只能出现在抽象类中
// 抽象类中必须包含至少一个抽象方法,不然没有意义
// 抽象类和抽象方法用来定义标准,基类要求他的子类必须包含某种方法
class Linfeng5 extends People9{
    constructor(name:string){
        super(name)
    }
    // 父类定义了  write 方法  子类必须包含这个方法  否则报错:非抽象类“Linfeng5”不会实现继承自“People9”类的抽象成员“write”。
    write():string{
        return this.name + '在写论文';
    }
    eat():string{
        return this.name + '在吃饭';
    }
}
let lf10 = new Linfeng5("临枫哇");
// console.log(lf10.write());//打印:临枫哇在写论文

 

// ts中的接口       定义标准,定义了行为和动作的规范   对批量方法进行约束

 

 

// ts中的接口       定义标准,定义了行为和动作的规范   对批量方法进行约束

// 定义一个接口  关键字  interface
interface Tset1{
    name:string;
    age:number
}
// 传入方法的参数必须要满足接口规定的参数
function fn15(people:Tset1){
    console.log(people.name + '今年' + people.age + '岁了');
}


///  这样写会报错 类型“{ name: string; age: number; sex: number; }”的参数不能赋给类型“Tset1”的参数。对象文字可以只指定已知属性,并且“sex”不在类型“Tset1”中。
// fn15({
//     name:'临枫',
//     age:18,
//     sex:1
// })



// 所以我们建议这样写
// 传入参数必须包含 接口定义的  sting 类型的 namge  和 number 类型的 age  
let _obj = {
    name:'临枫',
    age:18,
    sex:1
}

// fn15(_obj); //输出:临枫今年18岁了


// ts的接口  对批量方法进行约束

function fn16(people:Tset1){
    console.log(people.name + '性别' + sex?'男':'女' + '今年' + people.age + '岁了');
    // 还没开始调用  这里就报错了   报错 :  找不到名称“sex”  
    // 也就是说必须按照接口约束的参数传入  多一个少一个 都不行   参数可以多传  但是不能去使用
}

 

案例:通过接口  封装一个jquery的 ajax

// 案例: 封装一个请求数据的 ajax的接口

interface Config{
    type:string,
    url:string,
    data?:string
    dataType:string
}

class ${
    constructor(){

    }
    static ajax(config:Config){

        let xhr = new XMLHttpRequest();
        xhr.open(config.type,config.url,true);
        xhr.send(config.data);
        xhr.onreadystatechange = function(){
            if(xhr.readyState == 4 && xhr.status == 200){
                console.log("OK");

                if(config.dataType == 'json'){
                    console.log(JSON.parse(xhr.responseText))
                }else{
                    console.log(xhr.responseText)
                    
                }
            }

        }
    }
}

$.ajax({
    type:'get',
    url:'https://unpkg.com/live2d-widget-model-shizuku@1.0.5/assets/shizuku.model.json',
    dataType:'json',
    data:'啦啦啦'
})

// 输出:
// expressions: Array(4)
// 0: {name: "f01", file: "exp/f01.exp.json"}
// 1: {name: "f02", file: "exp/f02.exp.json"}
// 2: {name: "f03", file: "exp/f03.exp.json"}
// 3: {name: "f04", file: "exp/f04.exp.json"}
// length: 4
// __proto__: Array(0)
// hit_areas: (2) [{…}, {…}]

 

ts约束函数的接口


interface constraintFun{
    (name:string,age:number,sex?:boolean):object
}
let fn18:constraintFun = function(name:string,age:number):object{
    return {
        name:name,
        age:age
    }
}
console.log(fn18("临枫啊",18);)
// 输出:{name: "临枫啊", age: 18}
console.log(fn18("临枫啊",18);)
// 输出:{name: "临枫啊", age: 18}

ts 类类型接口  对类的约束   跟抽象类很像  (常用)

interface People10{
    name:string;
    study(book:string):string
}
    //     这不是继承这是实现  
class lf19 implements People10{
    name:string;
    constructor(name:string){
        this.name = name;
    }

    study(book:string){
        return this.name + '在学' + book;
    }
}
let fn19 = new lf19("临枫");
console.log(fn19.study("ts从精通到陌生"));
// 打印输出 :临枫在学ts从精通到陌生 
 
 

ts中 接口的扩展  接口的继承 (接口完结篇)

 

interface People19 {
    study(): void;
}

interface Ultraman extends People19 {
    play(): void;
}

class Programma{
    name:string;
    constructor(name:string){
        this.name = name
    }
    coding(code:string){
        console.log(this.name + code)
    }
}

class Dijia extends Programma implements Ultraman {
    constructor(name: string) {
        super(name)
    }
    // 继承父类  并使用了 Ultraman 继承People19的接口  所以必须包含 play 和study方法
    play(){

    }
    study(){

    }
}

 

 

ts泛型的定义

软件工程中,我们不仅要创建一致的定义好的API,同时也要考虑可重用性,组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能
在像c#和java中,可以使用泛型来创建可重用的组件,一个组件可支持多种类型的数据,这样用户就可以以自己的数据类型来使用组件
通俗理解:泛型就是解决 类 接口 方法的重用性、以及对不特定数据类型的支持
可以支持不特定的数据类型
// 传入number类型  必须返回 number 传入 string 必须饭string

// 泛型  可以支持不特定的数据类型 
// 传入参数和返回参数一致
// T表示泛型  具体什么类型是调用这个方法时候决定的
function fn24<T>(val:T):T{
    return val
}
fn24<string>('123')
fn24<number>(123)

function fn25<T>(val:T):any{
    return val
}
fn25<string>('这是一个泛型')
console.log(fn25<number>(123))

 

/泛型类

class MinNum<T>{
    public list: T[] = [];
    add(num: T) {
        this.list.push(num)
    }
    min() {
        let minNum = this.list[0];
        for (let i = 0; i < this.list.length; i++) {
            if (minNum > this.list[i]) {
                minNum = this.list[i]
            }
        }
        return minNum
    }
}

let lf22 = new MinNum<number>();
lf22.add(116);
lf22.add(2);
lf22.add(5);
lf22.add(78);
lf22.add(879);
// console.log(lf22.min()) //输出 : 2
let lf23 = new MinNum<string>();
lf23.add('你好啊');
lf23.add('我叫赛丽亚');
lf23.add('今天也是');
lf23.add('不出史诗的一天');
// console.log(lf23.min()) //输出 : 不出史诗的一天
 
 定义泛型接口
 
interface Fun02{
    <T>(val:T):T
}
let runing01:Fun02 = function<T>(a:T):T{
    return a
}
runing01<string>("啦啦啦");
runing01<number>(123);

// 第二种方法
interface Fun03<T>{
    (val:T):T
}
function runing02<T>(a:T):T{
    return a
}
let myRuning02:Fun03<string> = runing02;
myRuning02('20');

 

把类作为参数  结合泛型类 来约束数据传入的类型

class User{
    name:string | undefined;
    token:string | undefined;
    userId:number | undefined;
}

class SqlDb{
    add(info:User):boolean{
        console.log(info);
        return false
    }
}

let u = new User();
u.name = '临枫';
u.token = 'LinF0120',
u.userId = 154;

let db = new SqlDb();
db.add(u);
// 打印: User {name: "临枫", token: "LinF0120", userId: 154}



class People25{
    name:string | undefined;
    sex:boolean | undefined;
    age:number | undefined;
}

class Sql02<T>{
    add(user:T):boolean{
        console.log(user)
        return true
    }
}

let lf25 = new People25();
lf25.name = '临枫';
lf25.sex = true;
lf25.age = 18;


// let sql = new Sql02();
// sql.add('56454');//传错误类型  但是不报错

let sql = new Sql02<People25>(); //这样就不报错了
sql.add(lf25);

 

模块  把一些公共的功能单独抽离成一个文件作为一个模块

 

// 模块导出
    export function lf001(){
        console.log('lf001')
    }
    // 或者
    function lf0002(){
        console.log('lf002')
    }
    export { lf0002 }

 模块引入

 

// 引入模块
import { lf001, lf0002 as lalala } from "模块文件路径";
lf001();
lalala();

 

 

 命名空间       用于组织代码 避免命名冲突

 

namespace LF{
    interface User{
        name:string;
        age?:number;
        study():void;
    }
   export class People30 implements User{
        name:string;
        age:number;
        constructor(name:string,age:number){
            this.name = name;
            this.age = age;
        }
        study():void{
            console.log(this.name + '正在学习')
        }
    }
}

let lfy = new LF.People30("临枫",18);

lfy.study(); //临枫正在学习


namespace DY{
    interface User{
        name:string;
        age?:number;
        study():void;
    }
   export class People30 implements User{
        name:string;
        age:number;
        constructor(name:string,age:number){
            this.name = name;
            this.age = age;
        }
        study():void{
            console.log(this.name + '正在学习')
        }
    }
}

let Dy = new DY.People30("大眼",18);

Dy.study(); //大眼正在学习

 

ts的装饰器

 

// 装饰器是一种特殊类型的声明,他能够被附加到类声明,方法,属性或者参数上,可以修改类的行为。
// 通俗的将装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
// 常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
// 装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参)
// 装饰器是过去几年中js最大的成就之一,已经是ES7的标准特性之一


// 普通装饰器:
interface Folk {
    name: string;
    age?: number;
}
function APPConfig(params: any) {
    console.log(params);//params就是当前类
    params.prototype.motto = '今天学了习,明天更牛逼';
    params.prototype.say = function():void{
        console.log(this.name + this.motto)
    };
}
namespace LF {
    @APPConfig
    export class LinFengYa implements Folk {
        name: string;
        age?: number;
        constructor(name: string) {
            this.name = name
        }
        play():string{
            return this.name +"再也不打游戏了"
        }
    }
}
let xff:any = new LF.LinFengYa("小枫枫");
console.log(xff.play());  //输出 : 小枫枫再也不打游戏了
console.log(xff.motto);//这里会报错   指定xff为any类型就好了  输出:今天学了习,明天更牛逼
xff.say();//小枫枫今天学了习,明天更牛逼

 

 

// 装饰器工厂(可传参)

function LfConfig(params:any){
    return function(data:any){
        console.log(data);
        //打印 ƒ People31(name) {
        //     this.name = name;
        // }
        console.log(params);//打印www.linfengya.cn
        data.prototype.baseUrl = params;
    }
}

interface Folk0{
    name:string;
    age?:number;
}
@LfConfig("www.linfengya.cn")
class People31 implements Folk0{
    name:string;
    age?:number;
    constructor(name:string){
        this.name = name
    }
}

let xffy:any = new People31("临枫呀");

console.log(xffy.baseUrl);//输出 www.linfengya.cn

 

 使用类装饰器   重载构造函数  一个参数 即构造函数

function zsq(data: any) {
    console.log(data);
    return class extends data{
        apiUrl:any = '我被修改了额';
        getUrl(){
            return this.apiUrl;
        }
    }
}

@zsq
class HttpClient {
public apiUrl: string | undefined
    constructor() {
        this.apiUrl = 'www.linfengya.cn'
    }
    getUrl() {
        console.log(this.apiUrl)
    }
}

let linfeng:any = new HttpClient();
console.log(linfeng.getUrl()); //打印 我被修改了额

 

// 属性装饰器 表达式会在运势是当做函数被调用 传入一下两个参数:

//     1.对于静态成员来说是类的构造函数 对于实例的成员是类的原型对象
//     2.成员的名字

function lfProto(params:any) {
    return function(target:any,attr:any){
        console.log(target); //输出 :{getUrl: ƒ, constructor: ƒ}
        console.log(attr); // 输出: url
        console.log(params);//输出:  www.linfengya.cn
        target[attr] = params
        
    }
}

class People32{
    @lfProto("www.linfengya.cn")
    static url:string = '嘟嘟嘟嘟'
    constructor(){

    }
    static getUrl(){
        console.log(this.url);
    }
}

People32.getUrl();//输出  www.linfengya.cn

// 方法装饰器   三个参数  

 

function LfMethod(params:any){
    return function(target:any,methodName:any,desc:any){
        console.log(target);  //当前原型对象  {getUrl: ƒ, constructor: ƒ}
        console.log(methodName); //当前类中的方法
        console.log(desc);//描述{writable: true, enumerable: true, configurable: true, value: ƒ}
        target.testUrl = '滴滴滴滴滴';
        target.study = function(){
            console.log("学习");
        }


        console.log(desc.value);
        // 打印的是当前方法:
        // ƒ () {
        //     console.log(this.baseUrl);
        // }


        // 修改装饰器的方法  把装饰器方法传入参数改为string类型
        // 1.保存当前方法
        let oMethod = desc.value;
        desc.value = function(...args:any[]){
            args = args.map((v)=>{
                return v.toString();
            })
            console.log(args);//输出 (2) ["sds", "4444"]
            oMethod.apply(this,args)
        }

    }
}
class People33 {
    public baseUrl:string|undefined;
    constructor() {
        
    }
    @LfMethod('www.linfengya.cn')
    getUrl(...args:any[]){
        console.log('我是getUrl',args);
    }
}
let lf33:any = new People33();
lf33.getUrl('sds',4444); //打印    我是getUrl (2) ["sds", "4444"]

 

装饰器的执行顺序

 

// 装饰器执行顺序
// 属性 > 方法 > 方法参数 > 类
function logClass1(params:any){
    return function(target:any){
        console.log("类装饰器1");
        
    }
}

function logClass2(params:any){
    return function(target:any){
        console.log("类装饰器2");
    }
}
function logAttr(params?:any){
    return function(target:any,attrName:any){
        console.log("属性装饰器");
    }
}
function logMeth(params?:any){
    return function(target:any,attrName:any,desc:any){
        console.log("属性装饰器");
    }
}
function logParams(params?:any){
    return function(target:any,attrName:any,desc:any){
        console.log("方法参数装饰器1");
    }
}
function logParams2(params?:any){
    return function(target:any,attrName:any,desc:any){
        console.log("方法参数装饰器2");
    }
}
@logClass1("/*****")
@logClass2("------")
class HttpClient01{
    @logAttr()
    public url:any | undefined;
    constructor(){    
    }
    @logMeth()
    getData(@logParams("xxxx") uuid:any,@logParams2("xxxx") dd:any){
    }
}

var llllffff = new HttpClient01();

// 先后输出:
//              属性装饰器
// index.js:981 方法参数装饰器2
// index.js:976 方法参数装饰器1
// index.js:971 属性装饰器
// index.js:961 类装饰器2
// index.js:956 类装饰器1
本文最后更新于2020-6-8,已超过 1 年没有更新,如果文章内容或图片资源失效,请留言反馈,我们会及时处理,谢谢!
分享到:
打赏

作者: 小枫枫, 转载或复制请以 超链接形式 并注明出处 小枫枫不疯喔
原文地址: 《typeScript学习记录 (下)》 发布于2020-6-8

评论

切换注册

登录

您也可以使用第三方帐号快捷登录

切换登录

注册

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏