TypeScript 是什么

ts 是 js 的超集

❓ ts 相对于 js 的优势:

  1. 类型化思维方式,开发更加严谨,提前发现错误,减少改 bug 时间
  2. 类型系统提高了代码可读性,并使维护和重构代码更加容易
  3. 补充了接口,枚举等开发大型应用时 js 缺失的功能

ts 的环境准备

ts 的相关命令行

  1. npm install -g typescript
  1. tsc -v

创建并执行一个 ts 文件

  1. 创建一个 .ts 的文件

    1. var message:string = 'Hello World'
    2. console.log(message)
  2. 执行以下命令,将 TypeScript 转为 JavaScript

    1. tsc test.ts
  3. 使用 node 命令执行转换后的 .js 文件

    1. node test.js

    简化执行 ts 步骤

    简化方式一:使用 ts-node 包,

    “直接”在 node.js 或浏览器中执行 ts 代码(会在内部偷偷的调用)

  4. 安装命令

    1. npm i -g ts-node
  5. 使用方式

    1. ts-node hello.ts

    💞 ts-node 相当于 tsc 和 node 的整合
    image.png

    问题: 每次修改 ts 文件后,都要重新运行 tsc 命令将 ts 转换为 js

🈶解决方案:使用 tsc 命令的监视模式 tsc —watch test.ts

简化方式二:配置 vscode 编辑器,ts 转换 js

  1. 使用终端 cd 项目文件夹下,tsc —init 生成 tsconfig.json 文件
  2. 修改 tsconfig,json 的输出格式未 ./js

image.png

  1. 终端 → 运行任务 → typescript → tsc:监视tsconfig.json

image.png
如果 .ts 文件中没有ts语法,只有js代码,可以被直接在页面引入调用的。


下面要正式开始学习 ts 语法了啊!!!

TypeScript 语法

类型注解

  1. let age:number;
  2. // 数组的类型注解
  3. let names:string[] = []
  4. // 函数的类型注解
  5. function fn():number {}

问题: let img = documnet.querySelector(‘image’); img 获取到的类型为Element类型,只能调用公共的属性,比如id,获取不到src属性等; 因此就要用到了类型断言

类型断言:手动指定更加具体(精确)的类型

  1. let img = document.querySelector('img') as HTMLImageElement;
  2. img.src = './3.png'

💡当你不知道什么类型的时候,可以利用 console.dir() 查看类型

ts 中操作 dom 样式

  1. 在 ts 中,如果样式是两个单词,则使用驼峰法:

    1. let p = document.querySelector('p') as HTMLParagraphElement;
    2. p.style.fontSize = '30px';
  2. classList 属性(类样式)

    1. let p = document.querySelector('p') as HTMLParagraphElement;
    2. // 添加类
    3. p.classList.add('c', 'b')
    4. // 移除类
    5. p.classList.remove('b')
    6. // 判断类名是否存在
    7. let has = p.classList.contains('b')

    枚举类型

    枚举,可以防止出错,比如说:防止o写成0

    语法:enum 枚举名称 { 成员1, 成员2 } 约定枚举名称、成员名称以大写字母开头

  1. enum Gender {
  2. Female,
  3. Male
  4. }
  5. let userGender:Gender
  6. userGender = Gender.Female
  7. userGender = Gender.Male

💡注意:枚举的成员是只读的,因此,只能访问不能赋值

  1. 数字枚举:具有自增长行为
  2. enum Gender {
  3. Female,
  4. Male
  5. }
  6. // Female = 0 Male = 1
  7. enum Gender {
  8. Female = 100,
  9. Male
  10. }
  11. // Female = 100 Male = 101

🔈数字枚举:具有自增长行为

  1. 字符串枚举:没有自增行为,需要为每一个成员赋值
  2. enum Gender {
  3. Female = '女',
  4. Male = '男'
  5. }

🔈字符串枚举:没有自增行为,需要为每一个成员赋值

符号注意事项

  1. 除加号外,其他算术运算符必须与数字类型一起使用
  2. 在字符串类型的前面加上一个 ‘+’号,可以转换为 number 类型:

let n:number = +’12’

  1. console.log(3 === 4) // 会报错
  2. /* 正确用法 */
  3. let num1:number = 3
  4. let num2:number = 4
  5. console.log(num1 === num2) // false

ts 转换 js

  1. class Site {
  2. name():void {
  3. console.log('Hello World')
  4. }
  5. }
  6. var obj = new Site()
  7. obj.name()
  1. var site = /** @class */ (function() {
  2. function Site() {
  3. }
  4. Site.prototype.name = function() {
  5. console.log('Runoob')
  6. }
  7. return Site
  8. }())
  9. var obj = new Site()
  10. obj.name()

ts 基础类型

  • number
  • string
  • boolean
  • null 表示对象确实,能找到值
  • undefined 表示找不到值
  • void
    1. let name:string = 'Runoob'
    2. let years:number = 5
    3. let words:string = `您好,今年是${ name }发布${ years+1 }周年`
    4. let flag:boolean = true

    类型推论

    1. // 直接赋值,ts 是可以进行类型推论的 (age:number)
    2. let age = 18
    1. // 再次赋值,ts 是不会进行类型推论的 (age:any)
    2. let age
    3. age = 18

    定义数组的两种方式

    1. let arr1:number[];
    2. let arr2:Array<number>
    3. let arr3:any[] = ['123', '456', true]

    元组类型(tuple):属于数组的一种

    换种说法,就是在数组中,可以指定具体的类型
    1. let arr:[string, number, boolean] = ['ts', 3.08, true]

    any 任意类型

    1. var num:any = 123
    2. num = 'str'
    3. console.log(num)
    任意类型的用处:
    image.png

    null 和 undefined 是其他类型(never)的子类型

  1. 定义没有赋值的情况

    1. var num:number;
    2. console.log('num', num) // 语法报错,可采用以下写法
    3. var num:number | undefined;
    4. console.log((num);
  2. 定义 null 的情况

    1. var num:number | null;
    2. num = null
  3. 一个元素可能是 number 类型,也可能是 null 类型,也可能是 undefined 类型

    1. var num:number | null | undefined;
    2. num = 1234;
  4. void 类型:ts中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值

    1. function run():void {
    2. console.log('run')
    3. }
    4. run();
  5. never类型:是其它类型(包括null 和 undefined)的子类型,代表不会出现的值

这意味着声明 never 的变量只能被 never 类型所赋值

  1. var a:never;
  2. a = (() => {
  3. throw new Error('错误')
  4. })

ts 中函数的定义方法

函数声明法

  1. function run():string {
  2. return 'run';
  3. }
  1. function run(name:string, age:number):string {
  2. return `${name} --- ${age}`
  3. }
  4. run('zhangsan', 20)

函数匿名法

  1. var fun2 = function():number {
  2. return 123;
  3. }
  1. var fun2 = function(name:string, age:number):string {
  2. return `${name} --- ${age}`
  3. }
  4. fun2('zhangsan', 40)

方法可选参数:?:

es5里面方法实参和形参可以不一样,但是ts中必须一样,如果不一样就需要配置可选参数
💡注意:可选参数必须配置到参数的最后面

  1. function getInfo(name:string, age?:number):string {
  2. if(age) {
  3. return `${name} --- ${age}`
  4. } else {
  5. return `${name} --- 年龄保密`
  6. }
  7. }
  8. getInfo('zhangsan')

上述案例,因为少传一个参数,必须使用可选参数 ?:,否则 ts 语法报错

默认参数(可选参数)

es5 中不可以设置默认参数,es6 和 ts 中都可以设置默认参数

  1. function getInfo(name:string, age:number=20) {
  2. return `${name}---${age}`
  3. }
  4. getInfo('zhangsan')

剩余参数

  1. function sum(...result:number[]):number {
  2. var sum =0;
  3. for(var i=0; i<result.length; i++) {
  4. sum+=result[i]
  5. }
  6. return sum;
  7. }
  8. sum(1, 2, 3)
  1. function sum(a:number, ...result:number[]):number {
  2. var sum = a;
  3. for(var i=0; i<result.length; i++) {
  4. sum+=result[i]
  5. }
  6. return sum;
  7. }

函数重载

java 中方法的重载,重载指的是两个或者两个以上同名函数,但他们的参数不一样,会出现函数重载的情况。
ts 中的重载,通过为同一个函数提供多个函数类型定义来试下多种功能的目的。
ts 为了兼容 es5以及es6 重载的写法和 java中有区别

  1. function getInfo(name:string):string
  2. function getInfo(age:number):string
  3. function getInfo(str:any):any {
  4. if(typeof str === 'str') {
  5. return `name: ${str}`
  6. } else {
  7. return `age: ${str}`
  8. }
  9. }
  10. getInfo('zhangsan') // 正确写法
  11. getInfo(20) // 正确写法
  12. getInfo(true) // 错误写法

类和继承 extends super

  1. class Person {
  2. name:string;
  3. constructor(n:string) {
  4. this.name = n
  5. }
  6. run():void {
  7. alert(this.name)
  8. }
  9. }
  10. class Web extends Person {
  11. constructor(n:string) {
  12. // 初始化父类的构造函数
  13. super(n)
  14. }
  15. }
  16. var w = new Web('lisi')
  17. w.run()

类里面的修饰符

public 公有 在类里面、子类、类外面都可以访问
protected 保护类型 在类里面、子类里面可以访问,
在类外部没法访问
privated 私有 在类里面可以访问,子类、类外部都没法访问

属性如果没有设置,默认公有(public)

  1. class Person {
  2. protected name:string;
  3. private age:number;
  4. constructor(name:string) {
  5. this.name = name
  6. }
  7. // 类内部可以使用
  8. work():void {
  9. console.log(`${this.name}在工作`)
  10. }
  11. }
  12. class Web extends Person {
  13. constructor(name:string, age:number) {
  14. // 初始化父类的构造函数
  15. super(name, age)
  16. }
  17. // 子类内部可以使用
  18. run():void {
  19. console.log(`${this.name}在运动`)
  20. console.log(`年龄:${this.age}`)
  21. }
  22. }
  23. var w = new Web('lisi');
  24. w.run()
  25. w.work()
  26. var p = new Person()
  27. // 外部不可以访问,报错
  28. console.log('name', p.name)

ts 中的静态方法

  1. class Person {
  2. name:string;
  3. constructor(name:string) {
  4. this.name = name
  5. }
  6. // 实例方法
  7. run() {
  8. console.log(`奔跑的${this.name}`)
  9. }
  10. // 静态方法
  11. static print() {
  12. }
  13. }
  14. // 通过类名调用静态方法和属性
  15. Person.print()
  16. // 不能通过实例对象调用:
  17. const person = new Person('小甜甜')
  18. person.print()

多态

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

ts中的抽象类,它是提供其他类继承的基类,不能直接被实例化。
用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须派生在派生类中实现。
抽象方法只能放在抽象类里面。
抽象类和抽象方法用来定义标准,例如:Animal这个类要求它的子类必须包含eat方法

  1. // 抽象类
  2. abstract class Animal {
  3. name:string;
  4. constructor(name:string) {
  5. this.name = name
  6. }
  7. abstract eat():any
  8. }
  9. class Dog extends Animal {
  10. constructor(name:string) {
  11. this.name = name
  12. }
  13. // 必须定义 eat 方法
  14. eat() {
  15. console.log(`${this.name}在吃粮食`)
  16. }
  17. }
  18. var d = new Dog('小小')
  19. d.eat()

接口:行为和动作的规范,对批量方法进行约束

可利用接口代替繁琐的类型注解

  1. interface IPerson {
  2. firstname:string;
  3. lastname:string;
  4. sayHi()=>string
  5. }
  6. var customer:IPerson {
  7. firstname: "Tom",
  8. lastname: "Hanks",
  9. sayHi:():string => {
  10. return 'Hi Here'
  11. }
  12. }
  13. console.log('Customer 对象')
  14. console.log(customer.firstname)
  15. console.log(customer.lastname)
  16. console.log(customer.sayHi())
  17. /*
  18. 输出结果:
  19. Customer 对象:
  20. Tom
  21. Hanks
  22. Hi Here
  23. */

属性接口

  1. interface fullName {
  2. firstName:string; // 注意:以分号结束
  3. secondName:string;
  4. }
  5. function printName(name:fullName) {
  6. // 必须传入对象 firstName secondName
  7. console.log(name.firstName+'---'+name.secondName)
  8. }
  9. var obj = {
  10. age:20,
  11. firstName: '张',
  12. secondName: '三'
  13. }
  14. // 形式1在外部定义对象,可多传参数
  15. // 除了必传firstName,secondName,还可以传age
  16. printName(obj)
  17. // 形式2,严格按照对应方式
  18. // 只能传firstName,secondName
  19. printName({
  20. firstName:'zhang',
  21. secondName: 'san'
  22. })

接口:可选属性

  1. interface fullName {
  2. firstName:string;
  3. // 可选属性
  4. secondName?:string;
  5. }
  6. function printName(name:fullName) {
  7. console.log('name', name.firstName)
  8. }
  9. var obj = {
  10. firstName" 'zhang'
  11. }
  12. printName(obj)

接口:函数类型接口

对方法传入的参数及返回值进行约束(批量约束)
加密的函数类型接口

  1. interface screCN {
  2. (key:string, value:string):string
  3. }
  4. var md5:screctN = function(key:string, value:string):string {
  5. return key+value
  6. }
  7. console.log(md5('name', 'zhangsan'))

可索引接口:数组、对象的约束(不常用)

  1. // 可索引接口:对数组的约束
  2. interface userArr {
  3. [index:number]:string
  4. }
  5. var arr:userArr = ['zhang', 'san']
  6. console.log(arr[0])
  1. // 可索引接口:对对象的约束
  2. interface userObj { // 很少用
  3. [index:string]:string
  4. }
  5. var arr:userObj = {
  6. name: '张三'
  7. }

类类型接口

对类的约束和抽象类有点相似
关键词:implements

  1. interface Animal {
  2. name:string;
  3. eat():void;
  4. }
  5. class Dog implements Animal {
  6. name:string;
  7. constructor(name:string) {
  8. this.name = name;
  9. }
  10. eat() {
  11. console.log(`${this.name}吃两素`)
  12. }
  13. }
  14. var d = new Dog('小黑')
  15. d.eat()

接口扩展

接口继承接口

  1. interface Animal {
  2. eat():void;
  3. }
  4. interface Person extends Animal {
  5. work():void;
  6. }
  7. class Web implements Person {
  8. name:string;
  9. constructor(name:string) {
  10. this.name = name
  11. }
  12. work() {
  13. console.log(`${this.name}在工作`)
  14. }
  15. eat() {
  16. console.log(`${this.name}在吃饭`)
  17. }
  18. }

继承类,实现接口继承

  1. interface Animal {
  2. eat():void;
  3. }
  4. interface Person extends Animal {
  5. work():void;
  6. }
  7. class Programmer {
  8. name:string;
  9. constructor(name:string) {
  10. this.name = name;
  11. }
  12. code() {
  13. console.log(`${this.name}在写代码`);
  14. }
  15. }
  16. class Web extends Programmer implements Person {
  17. constructor(name:string) {
  18. super(name)
  19. }
  20. eat() {
  21. console.log(`${this.name}在吃饭`)
  22. }
  23. work() {
  24. console.log(`${this.name}在工作`)
  25. }
  26. }
  27. var w = new Web('小李')
  28. w.code()

类和接口

类可以实现接口,使用关键字 implements,并将 interest 字段作为类的属性使用

  1. interface IAron {
  2. interest:number
  3. }
  4. class Aro implements IAron {
  5. interest:number;
  6. rebate:numner;
  7. constructor(interest:number, rebate:number) {
  8. this.interest = interest;
  9. this.rebate = rebate
  10. }
  11. }
  12. var obj = new Aro(10, 1);
  13. console.log("利润:", obj.interest, "提成:", obj.rebate)

泛型

可以支持不特定的数据类型
要求:传入的参数和返回的参数一致
T表示泛型(A也可以表示),具体什么类型是调用这个方法的时候决定的

  1. function getData<T>(value:T):T {
  2. return value;
  3. }
  4. getData<number>(123);
  5. getData<string>('123');
  6. getData<string>(123);

泛型类

  1. // 无论传入数字还是字符串,判断大小,返回最小的元素
  2. class MinClass<T> {
  3. list:T[] = []
  4. add(value:T):void {
  5. this.list.push(value)
  6. }
  7. min():T {
  8. var minNum = this.list[0]
  9. for(var i=0; i<this.list.length; i++) {
  10. if(minNum > this.list[i]) {
  11. minNum = this.list[i]
  12. }
  13. }
  14. return minNum
  15. }
  16. }
  17. // 实例化类,并且制定了类的T代表的类型是Number
  18. var m1 = new MinClass<number>();
  19. m1.add(11);
  20. m1.add(12);
  21. m1.min();
  22. // 实例化类,并且制定了类的T代表的类型是string
  23. var m2 = new MinClass<string>();
  24. m2.add('a');
  25. m2.add('b');
  26. m2.min();

泛型接口

  1. interface ConfigFn {
  2. // 任意类型的函数,返回任意类型的值
  3. <T>(value:T):T
  4. }
  5. var getData:ConfigFn = function<T>(value:T) {
  6. return value;
  7. }
  8. getData<string>('123');
  9. getData<string>(123);

把类作为参数的泛型类

  1. // 定义数据库泛型类
  2. class MysalDB<T> {
  3. add(info:T):boolean {
  4. console.log(info)
  5. return true;
  6. }
  7. }
  8. /**********************方式1************************/
  9. class User {
  10. name:string | undefined;
  11. password:string | undefined;
  12. }
  13. var u - new User();
  14. u.name = '张三';
  15. u.password = '123456';
  16. // 将User类作为数据库类的参数
  17. var db = new MysqlDB<User>();
  18. db.add(u);
  19. /***********************方式2**********************/
  20. class Articles {
  21. title:string | undefined;
  22. desc:string | undefined;
  23. sttus:string | undefined;
  24. // 构造函数另一种方式
  25. constructor(params:{
  26. title:string | undefined;
  27. desc:string | undefined;
  28. status?:string | undefined
  29. }) {
  30. this.title = params.title;
  31. this.desc = params.desc;
  32. this.status = params.status
  33. }
  34. }
  35. // 实例化文章类
  36. var a = new Articles({
  37. title: '分类',
  38. desc: '111'
  39. })
  40. var db = new MysqlDB<Articles>();
  41. db.add(a)

综合案例:模块 → 封装DB类库

封装数据库DB类库,到处数据库类

  1. 文件目录:module/db.ts
  2. interface DBI<T> {
  3. add(info:T):boolean;
  4. }
  5. export class MysalDB<T> implements DBI<T> {
  6. constructor() {
  7. console.log('数据库已连接!')
  8. }
  9. add(info:T):boolean {
  10. console.log(info);
  11. return true;
  12. }
  13. }

封装User模块类,对数据库模块类进行映射,到处User类

  1. 文件目录:model/user.ts
  2. import { MysqlDB } from '../modules/db';
  3. class UserClass {
  4. username:string | undefined;
  5. password:string | undefined;
  6. }
  7. var UserModel = new MysqlDBI<UserClass>();
  8. export {
  9. UserClass,
  10. UserModel
  11. }

index.ts 页面使用User模块类

  1. import { UserClass, UserModel } from '../model/user'
  2. var u = new UserClass()
  3. u.username = 'zhangsan'
  4. u.password = '123456'
  5. UserModel.add(u)

命名空间和模块的区别

命名空间:内部模块,主要用于组织代码,避免命名冲突。(namespace)
模块:ts 的外部模块的构建,侧重于代码的复用,一个模块里可能有多个命名空间。

  1. namespace A {
  2. interface Animal {
  3. name:string;
  4. eat():void;
  5. }
  6. export class Dog implements Animal {
  7. name:string;
  8. constructor(name:string) {
  9. this.name = name;
  10. }
  11. eat() {
  12. console.log(`${this.name}在吃`)
  13. }
  14. }
  15. }
  16. namespace B {
  17. interface Animal {
  18. name:string;
  19. eat():void;
  20. }
  21. export class Dog implements Animal {
  22. name:string;
  23. constructor(name:string) {
  24. this.name = name;
  25. }
  26. eat() {
  27. console.log(`${this.name}在吃饭呢`)
  28. }
  29. }
  30. }
  31. var d = new A.Dog('小黑');
  32. d.eat(); // 小黑在吃

命名空间也可以单独封装,到处使用

  1. // 封装命名空间
  2. export namespace A {
  3. interface Animal {
  4. name:string;
  5. eat():void;
  6. }
  7. export class Dog implements Animal {
  8. name:string;
  9. constructor(name:string) {
  10. this.name = name;
  11. }
  12. eat() {
  13. console.log(`ths.name`在吃狗粮)
  14. }
  15. }
  16. }
  1. // 使用封装的命名空间
  2. import { A } from './Animal'
  3. var d = new A.Dog('二哈')
  4. d.eat()

装饰器

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

类装饰器

类装饰器在类声明之前被声明(紧靠着类声明)。类装饰器应用于构造函数,可以用来监视,修改或替换类定义。传入一个参数

  1. // 普通装饰器:无法传参
  2. function logClass(params:any) {
  3. console.log(params)
  4. // 扩展属性
  5. params.prototype.baseUrl = '******';
  6. // 扩展方法
  7. params.prototype.eat = function() {
  8. console.log('一直在吃')
  9. }
  10. }
  11. @logClass // 调用装饰器
  12. class HttpClient {
  13. constructor() {}
  14. getData() {}
  15. }
  16. var http:any = new HttpClient();
  17. console.log(http.baseUrl) // ******
  18. http.eat() // 一直在吃
  1. // 装饰器工厂(传参)
  2. function logClass(params:string) {
  3. return function(target:any) {
  4. console.log('参数', params) // hello
  5. console.log('类', target) // HttpClient
  6. target.prototype.apiUrl = '1234567'
  7. }
  8. }
  9. @logClass('hello')
  10. class HttpClient {
  11. constructor() {}
  12. getData() {}
  13. }
  14. var http:any = new HttpClient()
  15. console.log(http.apiUrl) // 1234567

装饰器重载类构造函数和方法

  1. function logClass(target:any) {
  2. return class extends target {
  3. apiUrl:any = '我是修改后的apiUrl'
  4. getData() {
  5. console.log(this.apiUrl)
  6. }
  7. }
  8. }
  9. @logClass
  10. class HttpClient {
  11. apiUrl:string | undefined;
  12. constructor() {
  13. this.apiUrl = '我是构造函数里的apiUrl'
  14. }
  15. getData() {
  16. console.log(this.apiUrl)
  17. }
  18. }

属性装饰器

属性装饰器表达式会在运行时当做函数被调用,传入下列2个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  2. 成员的名字 ```typescript function logProp(params:any) { return function(target:any, attr:any) { target[attr] = params; } }

class HttpClient { // 调用属性装饰器 @logProp(‘www.baidu.com’) url:string | undefined; constructor() {} // 经过属性装饰器,现在url有默认值 getData() { console.log(this.url) } }

var http = new HttpClient(); http.getData()

  1. <a name="jaEXg"></a>
  2. #### 方法装饰器
  3. **它会被应用到方法的属性描述符上,可以用来监视,修改或替换方法定义。**<br />**方法装饰器会在运行时传入下列3个参数:**
  4. 1. **对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。**
  5. 1. **成员的名字。**
  6. 1. **成员的属性描述符。**
  7. ```typescript
  8. function get(params:any) {
  9. return function(target:any, methodName:any, desc:any) {
  10. target.apiUrl = 'xxxxxx'
  11. target.run = function() {
  12. console.log('run')
  13. }
  14. }
  15. }
  16. class HttpClient {
  17. url:any | undefined;
  18. constructor() {}
  19. // 调用方法选择器
  20. @get('www.baidu.com')
  21. getData() {
  22. console.log(this.url)
  23. }
  24. }
  25. var http:any = new HttpClient()
  26. http.run()
  1. // 修改当前类的方法
  2. function get(params:any) {
  3. return function(target:any, methodName:any, desc:any) {
  4. // 1. 保存当前的方法
  5. var oMethod = desc.value
  6. desc.value = function(...arrs:any[]) {
  7. arrs = arrs.map(value => {
  8. return String(value);
  9. })
  10. // 对象冒充
  11. oMethod.apply(this, arrs)
  12. }
  13. }
  14. }
  15. class HttpClient {
  16. constructor() {}
  17. getData(...args:any[]) {
  18. console.log(arrs)
  19. console.log('我是getData里面的方法')
  20. }
  21. }
  22. var htto = new HttpClient()
  23. http.getData(123, 'xxx')

方法参数装饰器

参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
  2. 参数的名字
  3. 参数在函数参数列表中的索引 ```typescript function logParams(params:any) { return function(target:any, methodName:any, params:any) { target.apiUrl = params } } class HttpClient { constructor() {} // 调用方法参数装饰器 getData(@logParams(‘xxx’) uid:any) { console.log(‘uid’, uid) } }

var http = new HttpClient() htpp.getData(123456) console.log(http.apiUrl) ```

装饰器的执行顺序

属性 > 方法 > 方法参数 > 类
如果有多个同样的装饰器,它会先执行后面的装饰器