typescript基礎知識

Ts – 大地老師視頻筆記

Ts數據類型

typescript中爲了使編寫的代碼更規範,更有利於維護,增加了類型校驗,寫Ts代碼必須指定類型

布爾類型

var flag:boolean = true
// flag = 123 錯誤寫法
flag = false
console.log(flag);//false

數字類型

/**數字類型number */
let num:Number = 123
num = 456
console.log(num);

字符串類型

/**string類型 */
let str:String = 'sssss'
console.log(str);

數組類型

/**數組類型 */
//1.第一種定義數組的方式
let arr:Number[] = [11,12,13,14]//數組中的所有元素都是number類型
console.log(arr);
//2.第二種定義數組的方式
let arr1:Array<Number> = [11,12,13,14,15]//數組中的所有元素都是number類型
console.log(arr1);
//3.第三種定義數組的類型
let arr2:any[] = [11,12,13,'333',false]

元組類型

/**元組類型---屬於數組的一種 */
let arr2:[number, string,number,boolean] = [123,'234',222,false]
console.log(arr2);

枚舉類型

隨着計算機的不斷普及,程序不僅只用於數值計算,還更廣泛的用於處理非數值數據。例如:性別、月份、星期幾、顏色、單位名稱、簡歷、職業等,都不是數值數據,在其他程序設計語言中,一般用一個數值來代表某一狀態,這種處理方法不直觀,閱讀性差,如果能在程序中用自然語言中有相應含義的單詞來代表某一狀態,則程序就很容易閱讀和理解,也就是說,實現考慮到某一變量可能的取值,儘量用自然語言中涵義清楚地單詞來表示他的每一個值,這種方法稱爲枚舉法,用這種方法定義的類型爲枚舉類型

/**枚舉類型 */
/**
 * enum 枚舉名 {
 *  標識符[=整型常數]
 *  標識符[=整型常數]
 *  標識符[=整型常數]
 *  ...
 *  標識符[=整型常數]
 * }
 */
enum Flag {success=1, flase=2,pending}
let f:Flag = Flag.success
let f1:Flag = Flag.pending
console.log(f);//1
console.log(f1);//3
enum Color {blue, 'yellow', white}
let c:Color = Color.yellow
//如果標識符沒有賦值,那麼它的值就是下標
console.log(c);//1

任意類型(any)

/**任意類型(any) */
//1.基本使用
let n:any = 111
n = 'str'
n = true
console.log(n);
//2.用處:不加any會報錯
let obx:any = document.getElementById('id')
obx.style.color = 'red'

null和undefined — 其他數據類型(never類型)的子類型

/**null和undedined */
//let n1:number
//console.log(n1);//可以瀏覽器輸出,但Ts報錯
let n3:number | undefined
n3 = 12311
console.log(n3); //12311
//定義未賦值
let n4:number | undefined
console.log(n4); //undefined

let n5:null | number | undefined
n5 = 3333
console.log(n5);

void類型:Ts中的void表示沒有任何類型,一般用於定義方法的時候方法沒有返回值

/**void類型 */
//es5定義方法
function run () {
  console.log('run');
}
run()
//void定義方法:沒有返回值
function run1():void {
  console.log('run1');
}
run1()
//如果方法有返回值,返回值什麼類型就給方法指定什麼類型
function number():number {
  return 1
}
console.log(number());

never類型:代表從不會出現的值,這意味着聲明never的變量只能被never類型所賦值

/**never類型 --- 一般不用 */
let a:undefined
//a = 123 //報錯
a = undefined //正確

let b:null
//b = 222 //報錯
b = null //正確

let d:never
//d = 123 //報錯
a = (() => { //正確
  throw new Error('報錯')
})()

函數

/**函數 */
/**3.1 ES5定義函數兩種方法 */

1.函數聲明法
function run () {
  return 'run'
}
//2.匿名函數
let run2 = function () {
  return 'run2'
}

/**3.2 ts中函數定義方法 */
1.函數聲明法
function run():string {

  //return 123 //錯誤寫法
  return 'run'
}
//匿名函數寫法
let run2 = function ():number {
  return 123
}
alert(run2())
/**3.3 ts中定義方法傳參 */

function getInfo (name:string, age:number):string {
  return `${name} --- ${age}`
}
console.log(getInfo('111',23));

let get1 = function (name:string, age:number):string {
  return `${name} --- ${age}`
}
console.log(get1('www',45));
/**3.4 Ts方法的可選參數
 * 可選參數必須配置到參數最後面
 */
//1.ES5裏面的實參和形參可以不一樣,但Ts中必須一樣,如果不一樣,就需要配置可選參數
function getInfo (name:string, age?:number):string {//age加個?表示可選參數
    if (age) {
      return `${name} --- ${age}`
    } else {
      return `${name} --- 年齡保密`
    }
}
console.log(getInfo('111'));
/**3.5 Ts方法的默認參數
 * ES5沒有辦法設置默認參數,ES6和Ts中都可以設置默認參數
 */

function getInfo (name:string, age:number=20):string {//age加個?表示可選參數
    if (age) {
      return `${name} --- ${age}`
    } else {
      return `${name} --- 年齡保密`
    }
}
console.log(getInfo('111',40));
/**
 * 3.6 剩餘參數--三點運算符
 */
//1.三點運算符,接受形參傳過來的值
function sum (a:number, ...result:number[]):number {
  let sum = 0
  for(let i=0; i<result.length; i++) {
    sum += result[i]
  }
  return sum
}
console.log(sum(1,2,3,4,5));//14,把1賦值給了a
/**3.7 ts函數的重載
 * 1. java中的方法的重載:重載指的是兩個或兩個以上的同名函數,但他們的參數不一樣,這時會出現函數重載的情況
 * 2. Ts的重載:通過爲同一個函數提供多個函數類型定義,ts爲了兼容es5和es6,所以重載的寫法與java中有區別
 */
//ES5出現同名方法,下面的會替換上面的
// function css (config) {}
// function css (config, value) {}
//ts中的重載(1)
function getInfo (name:string):string;
function getInfo (age:number):number;
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)); //報錯,錯誤寫法
//ts中的重載(2)
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('wwwq',30));//正確
console.log(getInfo(222)); //錯誤
/**3.8 箭頭函數 es6 
 * this指向問題,箭頭函數裏面的this指向上下文
*/

ES5中的類和靜態方法以及繼承

/**ES5裏面的類 */
/** 1.對象冒充實現繼承  */
function Person () {
  this.name = 'ww'
  this.age = 30
  this.run = function () {} //實例方法
}
Person.getInfo = function () {} //靜態方法
Person.prototype.work = function () {} //
Person.getInfo() //調用靜態方法
const p = new Person()
console.log(p.name);
//web類繼承Person類  原型鏈+對象冒充的組合繼承模式
function Web () {
  Person.call(this) //對象冒充實現繼承
}
let w = new Web()
w.run() //調用Person的run方法,對象冒充可以繼承構造函數裏面的屬性和方法
w.work() //報錯,對象冒充沒法繼承原型鏈上的屬性和方法
/** 2.原型鏈實現繼承 
 *   問題:實例化子類的時候沒法給父類傳參
 */
function Person () {
  this.name = 'ww'
  this.age = 30
  this.run = function () {} //實例方法
}
Person.getInfo = function () {} //靜態方法
Person.prototype.work = function () {} //
Person.getInfo() //調用靜態方法
const p = new Person()
console.log(p.name);
function Web () {}
Web.prototype = new Person() //原型鏈實現繼承,即可以繼承構造函數中的屬性和方法,也可以繼承原型鏈上的屬性和方法
let w = new Web()
w.run()//正確
w.work() //正確
/** 3.原型鏈+構造函數的組合繼承模式 */
function Person (name, age) {
  this.name = name
  this.age = age
  this.run = function () {
        alert(this.name + '喫飯')
   } //實例方法
}
Person.getInfo = function () {} //靜態方法
Person.prototype.work = function () {} //
Person.getInfo() //調用靜態方法
const p = new Person()
console.log(p.name);
function Web (name, age) {
    Person.call(this, name, age) //對象冒充實現繼承,實例化子類可以給父類傳參
}
Web.prototype = new Person() //或者可以寫爲:Web.prototype = Person.prototype
let w = new Web('333',34) //實例化子類可以給父類傳參

ES6中的類

/** es6中定義類 */
class Person {
  //定義屬性,前面省略了public關鍵詞
  name:string
  constructor (name:string) { //構造函數,實例化類的時候觸發的方法
    this.name = name
  }
  run():void {
    alert(this.name)
  }
}
let p = new Person('張三')
p.run()

ts中的類

/**ts中定義類 */
class Person {
  //定義屬性,前面省略了public關鍵詞
  name:string
  constructor (name:string) { //構造函數,實例化類的時候觸發的方法
    this.name = name
  }
  getName():string {
    return this.name
  }
  setName(name:string):void {
    this.name = name
  }
}
let p = new Person('張三')
console.log(p.getName());
p.setName('李四')
console.log(p.getName());
/** 1.ts中實現繼承 -- extends  super*/
class Person {
  name:string
  constructor (name:string) {
    this.name = name
  }
  run():string {
    return `${this.name}在運動`
  }
}
class Web extends Person {
  constructor (name:string) {
    super(name)/**初始化父類構造函數 */
  }
}
let w = new Web('網五')
console.log(w.run());
/** 2.ts中繼承的探討 
 *   父類的方法和子類的方法一致 -- 先在子類中找
 * */
class Person {
  name:string
  constructor (name:string) {
    this.name = name
  }
  run():string {
    return `${this.name}在運動`
  }
  work():string {
    return `${this.name}在工作`
  }
}
class Web extends Person {
  constructor (name:string) {
    super(name)/**初始化父類構造函數 */
  }
  work():string {
    return `${this.name}在在在工作111`
  }
}
let w = new Web('網五')
console.log(w.run());
console.log(w.work());
/** 3.類裏面的修飾符
 * ts裏面定義屬性時,給我們提供了三種修飾符
 *   public -- 公有的,在當前類裏面,子類,類外面都可以訪問
 *   private -- 私有的,在當前類裏面可以訪問,子類和類外部無法訪問
 *   protected -- 保護類型 在當前類裏面和子類裏面可以訪問,類外部無法訪問
 *   屬性如果不加修飾符,默認是公有的
 */
/** 4.靜態屬性,靜態方法 */
class Person {
  name:string
  static age:number = 20 //靜態屬性
  constructor (name:string) {
    this.name = name
  }
  run () { //實例方法
    alert(`${this.name}在運動`)
  }
  work () { //實例方法
    alert(`${this.name}在工作`)
  } 
  static Print () { //靜態方法,在靜態方法中沒法調用類裏面的屬性,但可以調用靜態屬性
    console.log('qqq');
    console.log(Person.age + 'www');
  }
}
let p = new Person('張三')
Person.Print() //調用靜態方法
console.log(Person.age); //調用靜態屬性
/** 5.多態:父類定義一個方法不實現,讓繼承他的子類去實現,每一個子類有不同表現
 *  多態屬於繼承
 */
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}喫肉`
  }
}

class Cat extends Animal {
    constructor (name:string) {
      super(name)
  }
  eat () {
    return `${this.name}恥笑沒`
  }
}
/**6.抽象方法
 *  ts中的抽象類:是提供其他類繼承的基類,不能直接被實例化
 *  用abstract關鍵字定義抽象類和抽象方法,抽象類中的抽象方不包含具體實現並且必須在派生類中實現
 *  abstract抽象方法只能放在抽象類中
 */
abstract class Animal {
  name:string
  constructor (name:string) {
    this.name = name
  } 
  abstract eat():any
}
class Dog extends Animal {
  constructor (name:string) {
    super(name)
  }
  //抽象類的子類必須實現抽象類裏面的抽象方法
  eat () {
    console.log(`${this.name}喫糧食`);
  }
} 
let dog = new  Dog('小狗')
dog.eat()

接口

  1. 接口作用:在面向對象的編程中,接口是一種規範的定義,它定義了行爲和動作的規範,在程序設計裏面,接口起到一種限制和規範的作用,接口定義了一批類所需要遵守的規範,接口不關心這些類的內部狀態數據,也不關心這些類裏面方法的實現細節,他只規定這些類裏必須提供某些方法,提供這些方法的類就可以滿足實際需要
  2. interface定義接口
  3. 屬性類型接口
/**屬性接口 -- 對json的約束 */
//ts中自定義方法傳入參數時對json進行約束
function printLabel (labelInfo:{label:string}):void {
  console.log('printLabel');
}
printLabel({label : '張三'}) //正確寫法
//printLabel({name : 'ddd'}) //報錯,傳入的對象必須有label

//對批量方法傳入參數進行約束
interface FullName { //傳入對象的約束,屬性接口
  firstName:string
  secondName:string
}
function printName (name:FullName) {
  //要求 -- 必須傳入對象,對象中必須要有firstName和secondName
  console.log(name.firstName + '--' + name.secondName);
}
function printInfo (name:FullName) {
  console.log('--' + name.firstName + '--' + name.secondName + '--');
}
//printName(123) //報錯
const obj = { //傳入的參數必須包含firstName和secondName
  age : 20, 
  firstName : 'z',
  secondName : '3'
}
printName(obj)
printInfo(obj)

/**接口:可選屬性 */
interface FullName1 {
  firstName:string
  secondName?:string //加?表示該參數爲可選參數
}
function getName (name:FullName1) {
  console.log(name.firstName + '...' + name.secondName);
}
getName({
  firstName : '111'
})
getName({
  firstName : 'aaa',
  secondName : 'eee'
})
  1. 小案例
/**例子 */
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) {
      console.log('success');
      if (config.dataType == 'json') {
        JSON.parse(xhr.responseText)
      } else {
        console.log(xhr.responseText);
      }
    }
  }
}
ajax({
  type : 'get',
  url : 'http://www.baidu.com',
  dataType : 'json',
  data : 'name=123'
})
  1. 函數類型接口 – 對方法傳入的參數以及返回值進行約束,批量約束
/**函數類型接口 -- 對方法傳入的參數以及返回值進行約束 */
//加密的函數類型接口
interface encrypt {
  (key:string, value:string):string
}
let md5:encrypt = function (key:string, value:string):string {//必須滿足接口約束
  return (key + value)
}
console.log(md5('z','s'));
  1. 可索引接口
  • 對數組的約束
/**可索引接口 -- 對數組的約束 */
interface UserArr {
  [index:number]:string
}
let ar1:UserArr = ['aaa', 'bbb']
console.log(ar1[0]);
  • 對對象的約束
interface UserObj {
  [index:string]:string
}
let obj:UserObj = {
  name : '20',
  age : '20'
}
  1. 類類型接口
interface Animal1 {
  name:string
  eat1(str:string):void
}
class Dog1 implements Animal1 {
  name:string
  constructor (name:string) {
    this.name = name
  }
  eat1 () {
    console.log(this.name + '喫糧食');
  }
}
const dog1 = new Dog1('小黑')
dog1.eat1()
class Cat1 implements Animal1 {
  name:string;
  constructor (name:string) {
    this.name = name
  }
  eat1 (food:string) {
    console.log(this.name + '喫' + food);
  }
}
let ca = new Cat1('小花')
ca.eat1('老鼠')
  1. 接口的擴展 – 接口繼承接口
/** 接口的擴展 -- 接口可以繼承接口 */
interface Animal2 {
  eat ():void
}
interface Person extends Animal2 {
  work ():void
}
class Program {
  public name:string
  constructor (name:string) {
    this.name = name
  }
  coding (coding:string) {
    console.log(this.name + coding);
  }
}
class Man extends Program implements Person {
  constructor (name:string) {
    super(name)
  }
  eat () {
    console.log(this.name + '在喫飯');
  }
  work () {
    console.log(this.name + '在寫代碼');
  }
}

let m = new Man('小李')
m.eat() //小李在喫飯
m.work() //小李在寫代碼
m.coding('java')//小李Java

泛型

  1. 泛型:軟件工程中,我們不僅要創建一致的定義良好的API,同時也要考慮可重用性,組件不僅能夠支持當前的數據類型,同時也能支持未來的數據類型,這在創建大型系統時爲你提供了十分靈活的功能
  2. 在像C#和Java這樣的語言中,可以使用泛型來創建可重用的組件,一個組件可以支持多種類型的數據,這樣用戶就可以以自己的數據類型來使用組件
  3. 通俗的來說:泛型就是解決類、接口、方法的複用性、以及對不特定數據類型的支持
  4. 泛型的定義和泛型的函數
/** 泛型:可以支持不特定的數據類型  要求:傳入的參數和返回的參數一致 */
// T表示泛型,具體什麼類型是調用這個方法的時候決定的
function getDate<T>(value:T):T {
  return value
}
console.log(getDate<number>(123));
console.log(getDate<string>('222'));
  1. 泛型類
/** 泛型類:比如有個最小堆算法,需要同時支持返回數字和字符串兩種類型,通過類的泛型來實現*/ 
class MinClass<T> {
  public list:T[] = []
  add (num:T):void {
    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 m1 = new MinClass<number>() //實例化類,並且指定類的類型是number
m1.add(2)
m1.add(44)
m1.add(3)
m1.add(5)
m1.add(12)
console.log(m1.min())
let m2 = new MinClass<string>()//實例化類,並且指定類的類型是string
m2.add('12')
m2.add('13')
m2.add('14')
console.log(m2.min());
  1. 泛型類接口
//第一種定義泛型接口的方法
interface ConfigFn {
  <T>(value:T):T 
}
const setDate:ConfigFn = function <T>(value:T):T {
  return (value)
}
setDate<string>('123')
setDate<number>(1222)
//第二種定義泛型接口的方法
interface ConfigFn<T> {
  (value:T):T 
}
function getDate<T>(value:T):T {
  return (value)
}
let myGetDate:ConfigFn<string> = getDate
myGetDate('123')
  1. 把類作爲參數來約束數據傳入類型
/**
 * 定義一個User類,這個類的作用就是映射數據庫字段,
 * 然後再定義一個MsqlDb的類,這個類用於操作數據庫,
 * 然後把User類作爲參數傳入到MsqlDb
 */
/*普通寫法*/
class User {
  username:string | undefined; //不加undefined會報錯
  password:string | undefined
}
class MySqlDb {
  add (user:User):boolean {
    console.log(user);
    console.log(user.username);
    return true
  }
}
let u = new User()
u.username = '張三'
u.password = '122'
let my = new MySqlDb()
my.add(u)
/**泛型寫法*/
class User {
  username:string | undefined; //不加undefined會報錯
  password:string | undefined
}
//操作數據庫對額泛型類
class MySqlDb<T> {
  add (user:T):boolean {
    console.log(user);
    return true
  }
}
let u = new User()
u.username = '張三'
u.password = '1223'
//User類當作參數傳入泛型類中
let my = new MySqlDb<User>()
my.add(u)
//my.add('1223')//報錯
/*第三種寫法*/
class User {
  username:string | undefined; //不加undefined會報錯
  password:string | undefined
  constructor (params:{
    username:string | undefined
    password:string | undefined
  }) {
    this.username = params.username
    this.password = params.password
  }
}
class MySqlDb<T> {
  add (user:T):boolean {
    console.log(user);
    return true
  }
}
let u = new User({
  username : '張三',
  password : '12312'
})
//User類當作參數傳入泛型類中
let my = new MySqlDb<User>()
my.add(u)
  1. 小案例
/**
 * 功能:定義一個操作數據庫的庫,支持MySQL,Mssql, MongoDb
 * 要求:MySQL,Mssql, MongoDb功能一樣,都有add, delete, update, get方法
 * 注意:約束統一的規範以及代碼重用
 * 解決方案:需要約束規範所以要定義接口,需要代碼重用,所以要用到泛型
 *  
 */
interface DBI<T> {
  add (info:T):boolean;
  update (info:T, id:number):boolean;
  delete (id:number):boolean;
  get (id:number):any[] // 返回任意類型的數組
}
//定義一個操作MySQL數據庫的類
// 要實現泛型接口,這個類也應該是泛型類
class MySqlDb<T> implements DBI<T> {
  constructor () {
    console.log('建立數據庫鏈接');
  }
  add(info: T): boolean {
    console.log(info);
    return true
  }
  update(info: T, id: number): boolean {
    throw new Error("Method not implemented.");
  }
  delete(id: number): boolean {
    throw new Error("Method not implemented.");
  }
  get(id: number): any[] {
    let list = [
      {
        title: 'xxxx',
        dec: 'xxxxxxxx'
      },
      {
        title: 'xxxx',
        dec: 'xxxxxxx'
      }
    ]
    return list
  }
}
class MssqlDb<T> implements DBI<T> {
  add(info: T): boolean {
    console.log(info);
    return true
  }
  update(info: T, id: number): boolean {
    throw new Error("Method not implemented.");
  }
  delete(id: number): boolean {
    throw new Error("Method not implemented.");
  }
  get(id: number): any[] {
    let list = [
      {
        title: 'xxxx',
        dec: 'xxxxxxxx'
      },
      {
        title: 'xxxx',
        dec: 'xxxxxxx'
      }
    ]
    return list
  }
  
}
// 操作用戶表   定義一個user類和數據表映射
class User {
  username: string | undefined
  password: string | undefined
}
let u = new User()
u.username = '張三'
u.password = '2222'

let omysql = new MySqlDb<User>()
let omssql = new MssqlDb<User>()
//omysql.add(u)
omssql.add(u)
// 獲取ID=4的數據
let data = omssql.get(4)
console.log(data);

模塊

內部模塊

  1. 又稱命名空間
    • 在代碼量較大的情況下,爲了避免各種變量名相沖突,可將相似功能的函數類,接口等放置到命名空間內
    • 同Java包、.net的命名空間一樣,Ts的命名空間可以將代碼包裹起來,之對外暴露需要在外部訪問的對象,命名空間內的對象通過export導出

外部模塊 – 簡稱模塊

命名空間和模塊的區別

  1. 命名空間:內部模塊,主要用於組織代碼,避免命名衝突
  2. 模塊: ts外部模塊的簡稱,側重代碼的複用,一個模塊裏可能有多個命名空間

裝飾器

  1. 裝飾器是一種特殊類型的聲明,它能夠被附加到類聲明,方法,屬性或參數上,可以修改類的行爲
  2. 通俗的講,裝飾器就是一個方法,可以注入到類,方法,屬性參數上擴展類,屬性,方法,參數的功能
  3. 常見的裝飾器有:類裝飾器、屬性裝飾器、方法裝飾器、參數裝飾器
  4. 裝飾器的寫法:普通裝飾器(無法傳參),裝飾器工廠(可傳參)
  5. 裝飾器是過去幾年中js的最大成就之一,已經是ES7標準特性之一

類裝飾器

  1. 類裝飾器再類聲明之前被聲明(僅靠着類聲明),類裝飾器應用於類構造函數。可以用來監視,修改、替換類定義
  2. 普通裝飾器(無法傳參數)寫法
//類裝飾器 
function logClass (params:any) {
  console.log(params);
  // params就是當前類
  params.prototype.apiUrl = 'xxxxx' //動態擴展的屬性
  params.prototype.run = function () {
    console.log('我是run方法');
  }
}
@logClass
class HttpClient {
  constructor () {

  }
  getData() {

  }
}
let client:any = new HttpClient()
console.log(client.apiUrl);
console.log(client.run());
  1. 裝飾器工廠寫法
//裝飾器工廠
function logClass (params:string) {
  return function (target:any) {
    console.log(target); // 當前的類
    console.log(params); // 傳入的參數:hello
    target.prototype.ap = 'wwwww'
  }
}
@logClass('hello')
class HttpClient {
  constructor () {

  }
  getdata () {

  }
}
let ccc:any = new HttpClient()
console.log(ccc.ap);
  1. 小案例
/**
 * 重載構造函數的例子
 * 類裝飾器表達式會在運行時當作函數被調用,類的構造函數作爲其唯一參數
 * 如果類裝飾器返回一個值,他會使用提供的構造函數來替換類的聲明
 */
function logClass (params:any) {
  console.log(params); // 當前類
  return class extends params {
    apUrl:any = '我是修改後的URL'
    getData () {
      console.log(this.apUrl + '----');
    }
  }
}
@logClass
class HttpClient {
  public apUrl:string | undefined
  constructor () {
    this.apUrl = 'wwweee'
  }
  getData () {
    console.log(this.apUrl);
  }
}
let http = new HttpClient()
http.getData()

屬性裝飾器

  1. 屬性裝飾器表達式會在運行時當作函數被調用,傳入下列兩個參數
    • 對於靜態成員來說是類的構造函數,對於實例成員是類的原型對象
    • 成員名字
/**屬性裝飾器 */
function logProperty (params:any) {
  return function (target:any, attr:any) {
    console.log('attr:' + attr);
    console.log('屬性target:' + target);
    target[attr] = params
  }
} 
//類裝飾器
function logClass (params:any) {
  return function (target:any) {
    console.log('類target:' + target);
    console.log('params:' + params);
  }
}

@logClass('xxxx')
class HttpClient {
  @logProperty('xxxx222')
  public url:string | undefined
  constructor () {

  }
  getData () {
    console.log('url:' + this.url);
  }
}
let htt = new HttpClient()
htt.getData() // xxxx222

方法裝飾器

  1. 它會被應用到方法的 屬性描述符上,可以用來監視,修改或者替換方法定義
  2. 傳入一下參數:
    • 對於靜態成員來說是類的構造函數,對於實例成員是類的原型對象
    • 成員的名字
    • 成員的屬性描述符
/**方法裝飾器 */
function lgMessage (params:any) {
  return function (target:any, methodsName:any, desc:any) {
    console.log(target);
    console.log(methodsName);
    console.log(desc.value); // 當前的方法
    // target.apiUrl = 'llllg'
    // target.run = function () {
    //   console.log('我是run');
    // }
    /**修改裝飾器的方法 -- 把裝飾器裏面傳入的所有參數改爲string類型 */
    // 1.保存當前的方法
    let oMethods = desc.value
    // 2.修改方法
    desc.value = function (...args:any[]) { //使用三點運算符接收參數
      args = args.map((value) => {
        return String(value)
      })
      console.log(args);
      oMethods.apply(this, args)
    }
  }
}
class HttpClient {
  public url:string | undefined
  constructor () {

  }
  @lgMessage('methods')
  getData (...args:any) {
    console.log(args);//["1222", "3333"]
    console.log('我是getData裏面的方法');
  }
}
let h:any = new HttpClient()
// h.run()
// console.log(h.apiUrl);
h.getData('1222','3333') //["1222", "3333"] 我是getData裏面的方法

方法參數裝飾器

  1. 參數裝飾器表達式會在運行時當作函數被調用,可以使用參數裝飾器爲類的原型增加一些元素數據
  2. 參數如下:
    • 對於靜態成員來說是類的構造函數,對於實例成員是類的原型對象
    • 方法的名字
    • 參數在函數參數列表中的索引
/***參數裝飾器 */
function logParams (params:any) {
  return function (target:any, methodsName:any, paramsIndex:any) {
    console.log(params); //uuid
    console.log(target);
    console.log(methodsName);
    console.log(paramsIndex);
    target.apiUrl = params
  }
}
class HttpClient {
  public url:string | undefined
  constructor () {
  }
  getData (@logParams('uuid') uuid:any) {
    console.log(uuid); // 12345
  }
}
let h:any = new HttpClient()
h.getData(12345)
console.log(h.apiUrl); //uuid

裝飾器的執行順序

  1. 屬性 > 方法 > 方法參數 > 類
  2. 如果有多個同樣的裝飾器,會先執行後面的
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章