一文搞定TS高級語法(函數 類 多態 接口 泛型 裝飾器)

一、 函數

1. 定義函數

1. 函數聲明

//?爲可選參數 可選參數必須配置在最後面 
//可用默認參數,但不能和?用在一起
function fun1(name:string='li', age?:number):string{	//規定返回值爲string類型
    return `${name}--${age}`
}
console.log(fun1('san'))
console.log(fun1('san', 10))

2. 匿名函數

let fun2 = function():void{	//無返回值
    console.log(11)
}

3. 三點運算符的應用

function sum(...res:number[]):number{	//需要存在一個數組中
    let sum:number = 0
    for(let i = 0; i<res.length; i++){
        sum += res[i]
    }
    return sum
}
console.log(sum(1,2,3))

function ali(num1:number,...num2:number[]):number{  //三點運算符要放在最後面
    return num1
}
//數組第一個值放在num1中
console.log(ali(1,2,3))

二、 類

1. 類的定義

class Person{
    name:string
    constructor(n:string){  //構造器 實例化類的時候觸發的方法
        this.name = n
    }
    getName():string{
        return this.name
    }
    setName(name:string):void{
        this.name = name
    }
}
let p = new Person('li')
console.log(p.getName())
p.setName('zhang')
console.log(p.getName())

2. 類的繼承

class Person{
    name:string
    constructor(n:string){  //構造函數 實例化類的時候觸發的方法
        this.name = n
    }
    getName():string{
        return this.name
    }
    setName(name:string):void{
        this.name = name
    }
}
//繼承
class Web extends Person{
    constructor(name:string){
        super(name) //super表示調用父類的構造函數 constructor
        //將形參name存的值傳到Person構造器的n中
    }
    man(){  //不能用this.man = function(){}
        console.log('man')
    }
}
let w = new Web('wang')
console.log(w.getName())
w.man()

3. 類修飾符

1. 三種類修飾符

  • public: 公有 在類裏面 子類 類外面都可以訪問
  • protected: 保護類型 在類裏面 子類裏面可以訪問
  • private: 私有 類裏面可以訪問

2. 修飾符實例

class Person{
    public age:number = 20
    protected name:string
    private sex:string = 'male'

    constructor(age:number, name:string, sex:string){  //構造函數 實例化類的時候觸發的方法
        this.name = name
        this.age = age
        this.sex = sex
    }
    getName():string{
        return this.name
    }
    setName(name:string):void{
        this.name = name
    }
    getAge():void{
        console.log(this.age)   //類內訪問
    }
}
//繼承
class Web extends Person{
    constructor(age:number, name:string, sex:string){
        super(age, name, sex)
    }
    work(){
        console.log(this.name)  //訪問protected name
        // console.log(this.sex) 錯 不能訪問
    }
}
let p = new Person(20, 'li', 'male')
console.log(p.age)  //訪問public age
// console.log(p.name) 錯
// console.log(p.sex)   錯
let w = new Web(30, 'wang', 'female')
w.work()

4. 靜態方法 實例方法 靜態屬性

class Per{
    public name:string = 'wang'
    static age:number = 20
    constructor(name:string){
        this.name = name
    }
    run(){          //實例方法 只能通過實例調用
        console.log(`${this.name}在運動`)
    }
    static work(){  //靜態方法不能直接調用類裏的屬性,只能調用靜態屬性
        console.log(`我的年齡是${this.age}`)
    }
}
let p = new Per('wang')
p.run()
Per.work()  //靜態方法可以直接調用

5. 多態的表現-重載與重寫

1. 重載

1. 什麼是重載

就是函數或者方法有相同的名稱,但是參數列表不相同的情形,這樣的同名不同參數的函數或者方法之間,互相稱之爲重載函數或者方法

2. 重載的作用

不用爲了對不同的參數類型或參數個數,而寫多個函數。多個函數用同一個名字,但參數表,即參數的個數或(和)數據類型可以不同,調用的時候,雖然方法名字相同,但根據參數表可以自動調用對應的函數

3. 重載實例

function getInfo(name:string):string
function getInfo(age:number):string
function getInfo(str:any):any{
    if(typeof str === 'string') return '我叫 ' + str
    else return '我的年齡是 ' + str
}

console.log(getInfo('zhangsan'))
console.log(getInfo(20))
//console.log(getInfo(true))    //錯 沒有布爾型的函數聲明

//可選參數的重載
function get(name:string):string
function get(name:string, age:number):string
function get(name:any, age?:any):any{
    if(age) return '我叫 ' + name + '我的年齡是 ' + age
    else return '我叫 ' + name
}

console.log(get('li'))
// console.log(get(123)) 錯誤
console.log(get('li', 20))
// console.log(get('li', true))    錯誤

2. 重寫

1. 什麼是重寫

  • 發生在父類與子類之間
  • 方法名,參數列表,返回類型(除過子類中方法的返回類型是父類中返回類型的子類)必須相同
  • 訪問修飾符的限制一定要大於被重寫方法的訪問修飾符(public>protected>private)
  • 用子類中的方法代替父類中同名方法

2. 重寫實例

class Animal{
    name:string
    constructor(name:string){
        this.name = name
    }
    eat(){
        console.log('吃的方法')
    }
}
class Dog extends Animal{
    constructor(name:string){
        super(name)
    }
    eat(){
        return this.name + '吃骨頭'
    }
}
let d = new Dog('狗狗')
d.eat()

3. 抽象類

1. 什麼是抽象類

  • 抽象類它是提供其他類繼承的基類,不能直接被實例化 用abstract關鍵字定義抽象類和抽象方法,
  • 抽象類中的抽象方法不包含具體實現並且必須在派生類中實現,抽象方法只能放抽象類中
  • 用抽象類和抽象方法定義標準

2. 抽象類實例

abstract class Animal{
    public name:string
    constructor(name:string){
        this.name = name
    }
    abstract eat():any
}
// let a = new Animal() 錯誤 抽象類不能直接被實例化
class Dog extends Animal{
    //抽象類的子類必須實現抽象類中的抽象方法
    constructor(name:string){
        super(name)
    }
    changeName(){
        this.name = '阿貓阿狗'
        console.log(this.name)
    }
    eat(){
        console.log(this.name + '吃骨頭')
    }
}
let d = new Dog('狗狗')
d.eat()
d.changeName()

6. 接口 約束作用

1. 屬性接口

function printLabel(label:string):void{ //約束傳入字符串且無返回值
    console.log('print')
}
function print(labelInfo:{label:string}):void{
    console.log('labelInfo')
}

// print('haha')    錯誤
// print({name: 'haha'})    錯誤
print({label: 'wang'})

//interface關鍵字定義接口
interface FullName {
    firstName: string
    secondName?: string //可選屬性
}
function printName(name:FullName){  //必須傳入對象firstName secondName
    console.log(name.firstName + name.secondName)
}
// printName(20,'zhang','san') 錯 只能傳兩個字符串
let obj={
    age: 20,
    secondName: 'san',
    firstName: 'zhang'  //順序可以顛倒
}
printName(obj)  //可以

//接口實例作用 封裝 ajax
//約束了屬性的名字和類型
interface Config{
    type:string
    url:string
    data?:string
    dataType:string
}
function 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('success')
//JSON.stringify()的作用是將 JavaScript 對象轉換爲 JSON 字符串,而JSON.parse()可以將JSON字符串轉爲一個對象。
            if(config.dataType === 'json') JSON.parse(xhr.responseText)
            else console.log(xhr.responseText)
        }
    }
}
ajax({
    type:'get',
    data:'name=zhangsan',
    url:'www.baidu.com',
    dataType:'json'
})

2. 函數類型接口

//對方法傳入的參數及返回值進行約束
interface encrypt{
    (key:string, value:string):string
}
//名可以不同 但是類型得相同
let md5:encrypt = function(keys:string, values:string):string{
    return keys + values
}
console.log(md5('name', 'zhang'))

3. 可索引接口

//對數組、對象的約束
var arr:number[] = [222,333] 正常定義數組的方式
var arr1:Array<string> = ['222','333']

interface UserArr{
    [index:number]:string   //number是索引值的數據類型 string是value的數據類型
}
let arr:UserArr = ['aaa', 'bbb']
console.log(arr[0])

interface UserObj{
    [index:string]:string | number
}
let obj:UserObj = {name:'張三', age:20}

4. 類類型接口

//對類的約束 和 抽象類有點類似
interface Animal{
    name:string
    eat(str:string):void
}
class Dog implements Animal{
    name:string
    constructor(name:string){
        this.name = name
    }
    eat(){  //沒有參數也可以
        console.log(this.name + '吃骨頭')
    }
}
let d = new Dog('狗狗')
d.eat()
class Cat implements Animal{
    name:string
    constructor(name:string){
        this.name = name
    }
    eat(food:string){  //沒有參數也可以
        console.log(this.name + '吃骨頭')
    }
}
let c = new Cat('喵喵')
c.eat('food')

5. 接口繼承接口

interface Animal{
    getName():void
}
interface Person extends Animal{
   getFood():void
}
class Web implements Person{
    name:string
    food:string
    constructor(name:string, food:string){
        this.name = name
        this.food = food
    }
    getName(){
        console.log(this.name)
    }
    getFood(){
        console.log(this.name + '吃' + this.food)
    }
}
let w = new Web('小李', '米')
w.getFood()

6. 繼承結合接口

class Pro{
    work:string
    constructor(work:string){
        this.work = work
    }
}
class Code extends Pro implements Person{
    constructor(name:string, food:string, work:string){
        super(work)
    }
    getName(): void {
    }
    getFood(): void {
    }
}

7. 泛型

1. 泛型函數

function getData<T>(value:T):T{
    return value
}
getData<number>(123)
getData<string>('123')
//或者可以將返回值設爲any
function getNum<T>(value:T):any {
    return '1233'
}
getNum<number>(123)

2. 泛型類

class MinClass<T>{
    public list:T[] = []
    add(num:T){
        this.list.push(num)
    }
    min():T{
        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 m = new MinClass<number>()  //實例化類並且指定了T代表的類型是number

3. 泛型接口

//寫法1
interface ConfigFn{
    <T>(value:T):T
}
let getData:ConfigFn = function<T>(value:T):T{
    return value
}
getData<string>('12')
//寫法2
interface Config<T>{
    (value:T):T
}
function getData<T>(value:T):T{
    return value
}
let myGetData:Config<string> = getData
myGetData('2000')

4. 把類作爲參數來約束數據傳入的類型

//平常做法
class User{
    username:string | undefined
    password:string | undefined
}
class MysqlDB{
    add(user:User):boolean{
        console.log(user)
        return true
    }
}
let u = new User()
u.username = '張三'
u.password = '123'
let db = new MysqlDB()
db.add(u)

class User{
    username:string | undefined
    password:string | undefined
}
class MysqlDB<T>{
    add(info:T):boolean{
        console.log(info)
        return true
    }
}
let u = new User()
u.username = '張三'
u.password = '123'
let db = new MysqlDB<User>()    //驗證
db.add(u

8. 裝飾器

1. 什麼是裝飾器

  • 裝飾器 可以注入到類 方法 屬性參數上來擴展類 屬性 方法 參數的功能
  • 裝飾器寫法 普通裝飾器(無法傳參) 裝飾器工場(可傳參)

2. 類裝飾器

//在類聲明之前被聲明 緊靠着類聲明
//普通裝飾器
function logClass(params:any){
    console.log(params) //params就是當前類
    params.prototype.apiURL = '動態擴展的屬性'
    params.prototype.run = function(){
        console.log('這是一個run方法')
    }
}

@logClass
class HttpClient{
    constructor(){}
    getData(){}
}
let http:any = new HttpClient()
console.log(http.apiURL)
http.run()

//裝飾器工廠
function logClass(params:any){
    return class extends params{
        apiURL:string = '修改後的api'
        getData(){
            this.apiURL = this.apiURL + '--'
            console.log(this.apiURL)  //如果裏面
        }
    }
}

@logClass
class HttpClient{
    public apiURL:string | undefined
    constructor(){
        this.apiURL = '修改前的api'
    }
    getData(){
        console.log(this.apiURL)
    }
}
let http:any = new HttpClient()
console.log(http.apiURL)
http.getData()

3. 屬性裝飾器

function logProperty(params:any){
    return function(target:any, attr:any){
        console.log(target) //指向類
        console.log(attr)   //指向要修飾的屬性
        target[attr] = params
    }
}
class HttpClient{
    @logProperty('修改後的api')
    public url:any | undefined
    constructor(){}
    getData(){
        console.log(this.url)
    }
}
let p = new HttpClient()
p.getData()

4. 方法裝飾器

function get(params:any){
    return function(target:any, methodName:any, desc:any){
        console.log(target)
        console.log(methodName)
        console.log(desc)
        target.apiURL = '新增api'
        target.run = function(){
            console.log('新增方法')
        }
    }
}
class HttpClient{
    public url:any | undefined
    constructor(){}
    @get('www.baidu.com')
    getData(){
        console.log(this.url)
    }
}
let http:any = new HttpClient()
console.log(http.apiURL)
http.run()*/
//方法裝飾器將數組全部變成字符串
function get(params:any){
    return function(target:any, methodName:any, desc:any){
        console.log(target)
        console.log(methodName)
        console.log(desc)
        let oMethod = desc.value
        desc.value = function(...args:any[]){   //這麼寫是替換desc.value
            args = args.map((value)=>{  //而不是重寫
                return String(value)
            })
            console.log(args)
            oMethod.apply(this, args)   //重寫
        }
    }
}
class HttpClient{
    public url:any | undefined
    constructor(){}
    @get('www.baidu.com')
    getData(...args:any[]){
        console.log(args)
        console.log('我是getData裏面的方法')
    }
}
let http:any = new HttpClient()
http.getData(123, 'xx')

5. 參數裝飾器

function logParams(params:any){
    return function(target:any, methodName:any, paramsIndex:any){
        console.log(params)
        console.log(target)
        console.log(methodName)
        console.log(paramsIndex)
        target.apiURL = params
    }
}
class HttpClient{
    public  url:any | undefined
    constructor(){}
    getData(@logParams('xx') uuid:any){
        console.log(uuid)
    }
}
let http:any = new HttpClient()
http.getData('123')
console.log(http.apiURL)

6. 裝飾器注意點

  • 裝飾器執行順序 屬性>方法>方法參數>類
  • 同一種裝飾器由後向前 後近向遠執行
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章