美文网首页
typescript入门学习

typescript入门学习

作者: 王二麻子88 | 来源:发表于2020-10-13 22:31 被阅读0次

typescript入门学习

一. 数据类型

​ typescript中为了使编写的代码更规范,更有利于维护,增加了类型校验,在typescript中主要给我们提供了以下数据类型

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

注意!

在typescript中, 变量的数据类型一旦发生确定一般情况下就不能发生更改, any类型以及混合类型除外

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

或者

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

定义类型不进行赋值也会报错

var str:string;
console.log(str)  // 直接报错

1. 数组类型的定义方式

  1. 第一种定义方式

    var arr:number[]=[11,22,33];
    
  2. 第二种定义方式

    var arr:Array<number>=[11,22,33];  // 这种方式较为常用
    

2. 元组类型

值得一提的是: 元组类型是数组类型的一种

当存储的元素数据类型不同,则需要使用元组。(即一个数组里面既有数字类型, 又有字符串类型)

定义方式:

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

3. 可枚举类型

事先考虑到某一变量可能取的值,尽量用自然语言中含义清楚的单词来表示它的每一个值,

这种方法称为枚举方法,用这种方法定义的类型称枚举类型。

一般用来配置唯一标识符

语法:

enum 枚举名{ 
    标识符[=整型常数], 
        标识符[=整型常数], 
        ... 
    标识符[=整型常数], 
} ;     

关于可枚举对象的定义以及赋值问题

举个例子:

enum Flag {success=1,error=2};
let f:Flag=Flag.error;  //  注意取值定义的写法
console.log(f);  // 输出2

4. void类型

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

举个例子

//正确写法
function run():void{
    console.log('run')
}
run();

//错误写法
function run():undefined{
    console.log('run')
}
run();

// 当明确返回类型时
function run():number{
    return 123;
}
run();

5. never类型

never类型:是其他类型 (包括 null 和 undefined)的子类型,代表从不会出现的值。这意味着声明never的变量只能被never类型所赋值。

6. 不确定类型

一个元素可能是 number类型 可能是null 可能是undefined; 可以进行如下的定义

var num:number | null | undefined;

此时当定义 num变量但没有赋值时, num类型就是undefined, 而不是直接报错

二. 函数

1. 定义函数

声明函数
// 正确写法
function run():string{
  return 'run';
}

//错误写法
function run():string{
  return 123;
}
匿名函数
var fun2=function():number{
  return 123;
}

alert(fun2()); /*调用方法*/

2. 函数传参

// 声明式函数传参以及定义返回值
function getInfo(name:string,age:number):string{
    return `${name} --- ${age}`;
}

alert(getInfo('zhangsan',20));

// 匿名函数传参以及定义返回值
var getInfo=function(name:string,age:number):string{
    return `${name} --- ${age}`;
}
       
alert(getInfo('zhangsan',40));

// 函数没有返回值
function run():void{
   console.log('run')
}
run();
可选参数
// 用 形参名?type的形式, 表名参数是可选参数
function getInfo(name:string,age?:number):string{
    if(age){
        return `${name} --- ${age}`;
    }else{
        return `${name} ---年龄保密`;
    }
}
alert(getInfo('zhangsan'))
alert(getInfo('zhangsan',123))

注意:可选参数必须配置到参数的最后面

默认参数
function getInfo(name:string,age:number=20):string{
    if(age){
        return `${name} --- ${age}`;
    }else{
        return `${name} ---年龄保密`;
    }
}

alert( getInfo('张三'));
alert( getInfo('张三',30));
剩余参数

三点运算符 接受形参传过来的值

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

// 或者已明确几个参数, 其他参数剩余
function sum(a:number,b:number,...result:number[]):number{
    var sum=a+b;
    for(var i=0;i<result.length;i++){
        sum+=result[i];  
    }
    return sum;
}
alert(sum(1,2,3,4,5,6)) ;

3. 函数重载

typescript中的重载:通过为同一个函数提供多个函数类型定义来试下多种功能的目的。

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;
    }
}

4. 箭头函数

与js 一样, 箭头函数里面的this指向上下文

setTimeout(()=>{
    alert('run') // 
},1000)

三. 类

1. ES5原生JS继承

function Person(name,age){
    this.name=name;  /*属性*/
    this.age=age;
    this.run=function(){  /*实例方法*/
        alert(this.name+'在运动');
    }

}
Person.prototype.sex="男";
Person.prototype.work=function(){
    alert(this.name+'在工作');
}
       
      
function Web(name,age){
    Person.call(this,name,age);   //对象冒充继承  可以继承构造函数里面的属性和方法、实例化子类可以给父类传参
}

Web.prototype=Person.prototype;

var w=new Web('赵四',20);  

w.run();  // 输出 赵四在运动

2. 定义类

class Person{
    // 属性方法的权限修饰符默认是 public
    name:string;   //属性  前面省略了public关键词

    constructor(n:string){  //构造函数   实例化类的时候触发的方法
        this.name=n;
    }

    run():void{
        alert(this.name);
    }

}
var p=new Person('张三');

p.run()

3. ts中实现继承

class Person{

    name:string;

    constructor(name:string){
        this.name=name;
    }

    run():string{
        return `${this.name}在运动`
    }
}

var p=new Person('王五');
alert(p.run())


class Web extends Person{
    // 即 ES5中对象冒充对象实现继承父类传参
    constructor(name:string){
        // super函数可以不传参
        super(name);  /*初始化父类的构造函数*/
    }
}

var w=new Web('李四');
alert(w.run());

关于继承子类重写父类方法

class Person{
    // ts中定义类属性的方法
    name:string;
    
    constructor(name:string){
        this.name=name;
    }

    run():string{

        return `${this.name}在运动`
    }
}
var p=new Person('王五');
alert(p.run())


class Web extends Person{
    constructor(name:string){
        super(name);  /*初始化父类的构造函数*/
    }
    // run重写了继承父类的 run方法
    run():string{

        return `${this.name}在运动-子类`
    }
    work(){

        alert(`${this.name}在工作`)
    }
}

var w=new Web('李四');
alert(w.run());

w.work();
alert(w.run());

4. 权限修饰符

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

这三者的权限 public > protected > private


5. 静态属性

5.1 原生JS ES5定义静态方法和静态属性
function Person(){
    this.run1=function(){

    }
}
Person.name='哈哈哈';

Person.run2=function(){  // 静态方法


}
var p=new Person();

Person.run2(); // 静态方法的调用
5.2 ts定义静态方法和静态属性
class Per{
    public name:string;
    public age:number=20;
    //静态属性

    static sex="男";
    constructor(name:string) {
        this.name=name;
    }
    run(){  /*实例方法*/
        alert(`${this.name}在运动`)
    }
    work(){

        alert(`${this.name}在工作`)
    }
    static print(){  /*静态方法  里面没法直接调用类里面的属性*/

       alert('print方法'+Per.sex);
    }
}

var p=new Per('张三');

p.run();

Per.print();  // 调用静态方法

alert(Per.sex);  // 调用静态属性

6. 多态

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

与抽象类不同, 并不需要强制实现

多态属于继承

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+'吃老鼠'
    }
}

7. 抽象类

抽象类:它是提供其他类继承的基类,不能直接被实例化。

abstract 定义的抽象类不能实例化, 只能用于被继承

abstract class Animal{
    
    public name:string;
    constructor(name:string){

        this.name=name;

    }
    abstract eat():any;  //抽象方法不包含具体实现并且必须在派生类中实现。
    
    run(){

        console.log('其他方法可以不实现')
    }
}
/*错误的写法*/
var a=new Animal();  // 编译直接报错

上述的抽象类一般用法

class Dog extends Animal{

    //抽象类的子类必须实现抽象类里面的抽象方法
    constructor(name:any){
        super(name)
    }
    // 重写抽象类(更准确说实现抽象类)
    eat(){
        console.log(this.name+'吃粮食')
    }
}

var d=new Dog('小花花');
d.eat();


class Cat extends Animal{

    //抽象类的子类必须实现抽象类里面的抽象方法
    constructor(name:any){
        super(name)
    }
    run(){


    }
    // 重写抽象类(更准确说实现抽象类)
    eat(){

        console.log(this.name+'吃老鼠')
    }
}

var c=new Cat('小花猫');
c.eat();

继承抽象类的抽象方法, 必须实现, 不然直接编译报错

四. 接口

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

接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。

1. 属性接口

// 定义 对象属性接口
interface FullName{
    firstName:string;   //注意以;为结束, 不是js中以,为结束
    secondName:string;
}

function printName(name:FullName){
    // 必须传入对象  firstName  secondName
    console.log(name.firstName+'--'+name.secondName);
}
printName('1213');  // 错误 传入的参数必须是一个对象

/*传入的参数必须包含 firstName  secondName*/
var obj={
    age:20,
    firstName:'张',
    secondName:'三'
};
printName(obj)

2. 可选属性接口

interface FullName{
    firstName:string;
    secondName?:string;
}

function getName(name:FullName){

    console.log(name)
}  
getName({               
    firstName:'firstName'  // 其中secondName可以有也可以没有, 但一旦存在则必须是字符串类型
})

3. 属性接口应用

// 定义配置信息对象的接口
interface Config{
    type:string;
    url:string;
    data?:string;  // data属性可选
    dataType:string;
}

//原生js封装的ajax 
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'){
                console.log(JSON.parse(xhr.responseText));
            }else{
                console.log(xhr.responseText)
            }
        }
   }
}

// 调用接口
ajax({
    type:'get',
    data:'name=zhangsan',  // 此处的data可有可无
    url:'http://a.itying.com/api/productlist', //api
    dataType:'json'
})

4. 函数类型接口

函数类型接口: 对方法传入的参数以及返回值进行约束 批量约束

interface encypt{
    (key:string, value:string):string;  // 注意!, 这里是分号
}
// md5:encypt 规定了 md5这个函数参数类型以及返回类型
var md5:encypt = function (key, value):string{
    return key + ' ' + value // 模拟加密操作
}

5. 可索引接口

**可索引接口: **:数组、对象的约束

首先先回忆一下TS中定义数组的方式

// 第一种方法
var dataArr:number[] = [1, 2, 3, 4];

// 第二种方法
var dataArr1:Array<number> = [1, 2, 3, 4]

上述中的 number[]Array<number>可以看成是一个接口

  1. 对数组的约束

    interface UserArr{
        // 数组的索引是数字类型, 对应的值是字符串类型
         [index:number]:string
    }
    
    
    var arr:UserArr=['aaa','bbb'];
    
    console.log(arr[0]);
    
    
    var arr:UserArr=[123,'bbb'];  /*错误, 上述接口规定, 数组不能是数字 */ 
    
    console.log(arr[0]);
    
  2. 对对象的约束

    interface UserObj{
          [index:string]:string // 定义索引值类型为string, 内容为string类型
    }
    
    
    var arr:UserObj={name:'张三'};
    
    var arr1:UserObj = {name: 20}; // 报错
    

6. 类类型接口

**类类型接口: **对类的约束 和 抽象类抽象有点相似

// 定义类的接口
interface Animal{
    // 定义类的属性
    name:string;
    // 定义类的方法
    eat(str:string):void;
}

// 接口的实现, 与抽象类不同, 接口使用的是implements, 并且继承接口必须实现出来
class Dog implements Animal{

    name:string;
    constructor(name:string){
        // 实现属性
        this.name=name;
    }
    // 实现方法
    eat(){
       console.log(this.name+'吃粮食')
    }
}


var d=new Dog('小黑');
d.eat();


class Cat implements Animal{
    name:string;
    constructor(name:string){
        // 实现属性
        this.name=name;
    }
    // 实现方法
    eat(food:string){
        console.log(this.name+'吃'+food);
    }
}

var c=new Cat('小花');
c.eat('老鼠');

7. 接口扩展

**接口扩展: **接口可以继承接口

// 定义父类接口
interface Animal{
    eat():void;
}

// 子类继承父类接口, 使用 extends关键字
interface Person extends Animal{
    work():void;
}

// 实体类实现接口子类接口
class Web implements Person{
    public name:string;
    constructor(name:string){
        this.name=name;
    }
    // 实现父类接口(必须)
    eat(){
        console.log(this.name+'喜欢吃馒头')
    }
    // 实现子类接口(必须)
    work(){
        console.log(this.name+'写代码');
    }      
}

var w=new Web('小李');
w.eat();

五. 泛型

泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)

1. 定义泛型

首先回忆一下, TS中对函数返回类型的定义

// 只能返回string类型的数据
function getData(value:string):string{
    return value;
}

而当我们在不同场景下使用该函数, 既有可能返回数字类型, 又有可能返回字符串类型, 此时就必须用到函数的重载

// 同时返回 string类型 和number类型 
function getData1(value:string):string{
    return value;
}

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

当然了上述的代码就显得有点冗余, 用any数据类型确实可以解决, 但类型限制的意义又没有了

,基于此开始使用泛型的定义;

泛型:可以支持不特定的数据类型

要求:传入的参数和返回的参数一致

T表示泛型,具体什么类型是调用这个方法的时候决定的, 定义的时候是不明确具体的数据类型, 也就是说, 可以不同<T>表示用<A><B>都可以

// <T> 表示这个函数(方法)是一个泛型, 传入参数与返回参数必须一致
function getData<T>(value:T):T{
    return value;
}
getData<number>(123);

getData<string>('1214231');

/*错误的写法*/ 
getData<number>('2112');  // <T>泛型定义的是number类型 传入的却是string类型, 



function getData<T>(value:T):any{
    return '2145214214';
}

getData<number>(123);  //参数必须是number,
getData<string>('这是一个泛型'); // 参数必须是string

值得注意一点

function getData<T>(value:T):T{
    return "22323211";
}  
// 错误, 定义的是泛型,返回的就必须是泛型而不是数据类型, 即类型不能明确,返回类型可以用any表示

getData<string>('1214231');

2. 泛型类

// 需要同时支持返回数字和字符串 a  -  z两种类型
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(3);
m.add(22);
m.add(23);
m.add(6);

m.add(7);
alert(m.min());

上述类只能实现对number类型的传入与返回, 不支持字符串, 用类的泛型进行改装

//类的泛型

class MinClas<T>{

    public list:T[]=[];
    // 也可以这么描述
    // public list:Array<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;  // 此处返回的是通过 list:T[]定义的泛型
    }
}

/*实例化类 并且制定了类的T代表的类型是number*/
var m1=new MinClas<number>();   
m1.add(11);
m1.add(3);
m1.add(2);
alert(m1.min())

/*实例化类 并且制定了类的T代表的类型是string*/
// 泛型类实例化的规范 :   new Class<T>()
var m2=new MinClas<string>();

m2.add('c');
m2.add('a');
m2.add('v');
alert(m2.min())

3. 泛型接口

先来回忆一下函数类型接口

// 定义接口
interface ConfigFn{
    (value1:string,value2:string):string;
}

// 实现接口, value1必须存在且类型为string, 以此类推
var setData:ConfigFn=function(value1:string,value2:string):string{
    return value1+value2;
}

setData('name','张三');

泛型定义的接口

// 定义泛型接口
interface ConfigFn{
    <T>(value:T, value2: T):T;  // 规定这个value值是一个泛型
}

// 实现泛型接口
var getData:ConfigFn=function<T>(value:T, value2: T):T{
    return value+value2;
}

// 调用实现了泛型接口的函数
getData<string>('张三', "李四");

getData<string>(1243, "张三");  //错误, 定义string传入number

还有一种定义泛型接口方法:

interface ConfigFn<T>{
    (value:T):T;
}

// 定义函数类型泛型
function getData<T>(value:T):T{
    return value;
}

// 具名函数的变量中定义泛型
var myGetData:ConfigFn<string>=getData;     


myGetData('20');  /*正确*/


// myGetData(20)  //错误

六. 接口以及泛型的简单应用

场景: 定义一个操作数据库的类, 支持 mysql, MongoDB

**要求: ** mysql和mongodb的功能一致, 都有, add(), update, delete, get方法

// 首先定义操作数据方法的接口
// 因为接口不知道具体是mysql还是mongodb, 因此需要传入一个泛型
interface DBI<T> {
  add(info: T): boolean;
  update(info: T):boolean;
  delete(id:number): boolean;
  get(id:number):Array<any>;   // 注意接口的定义是用 ;分开来的
}

// 定义一个叫mysql数据库的类, 实现接口
// 传入实现的泛型类
// 注意, 要实现泛型接口, 实现的类也应该是一个泛型类
// 提示: Generic type 'DBI<T>' requires 1 type argument(s), 接口需要传入一个泛型
class MysqlDb<T> implements DBI<T> {
  add(info: T): boolean {
    console.log(info);
    return false;
  }

  delete(id: number): boolean {
    return false;
  }

  get(id: number): Array<any> {
    return undefined;
  }

  update(info: T): boolean {
    return false;
  }

}

// 操作一个用户表, 定义一个User类和数据库映射
class User {
  username: string | undefined;
  password: string | undefined;
}

const U = new User();
U.username = "wang";
U.password = "123456";

const Mysql1 = new MysqlDb<User>();  // 类作为参数来约束数据传入的类型

// Mysql1.add(U);

/*Mysql1.add({
  username: "wang",
  password: "123456"
});
//  也可以这么传值
*/

/*Mysql1.add({
  username1: "wang",
  password: "123456"
// 编译报错, 传入内容必须符合User类规范
});*/

七. 装饰器

1. 类装饰器

类装饰器:类装饰器在类声明之前被声明(紧靠着类声明)。

类装饰器应用于类构造函数,可以用来监视,修改或替换类定义

// 不传参
function logClass(params: any) {
  console.log(params);  // 输出 Function: Decoration1 指装饰器指向的类
  params.prototype.run = function ():void {
    console.log("在奔跑")
  }
}
@logClass
class Decoration1 {
  constructor(){
  }
  getData(){

  }
}

const d1:any = new Decoration1();  // 实例化的类型为 any类型
d1.run();  // 输出 "在奔跑"

// 传参, 装饰器工厂
// 定义装饰器工厂
function logClass(params:string) {
  return function (target: any) {
    console.log(params);  // 输出  https://wangermaizi.github.io
    console.log(target);  // 输出 Function: Decoration1
    target.prototype.baseUrl = params;
  }
}

// 加载装饰器
@logClass('https://wangermaizi.github.io')
class Decoration1{
  constructor(){
    // console.log(Decoration1.baseUrl);  // 报错,找不到装饰器上的baseUrl
  }

  getData(){

  }
}

const d1:any = new Decoration1();
console.log(d1.baseUrl);  // 输出 https://wangermaizi.github.io

由上可知, 类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数

2. 装饰器重载构造函数

// 定义装饰器
function logClass(target: any) {
  return class extends target{
    baseUrl:any = "222222222";
    get() {
      console.log("2222221111111")
    }
  }
}

@logClass   // 注意!!! 装饰器不传参的时候不要加上括号
class Decoration1 {
  public baseUrl:string | undefined;
  constructor() {
    this.baseUrl = "1111111"
  }
  get() {
    console.log("1111122222222")
  }
}

const d1:any = new Decoration1();
d1.get();  // 输出的是装饰器方法
console.log(d1.baseUrl);  // 输出装饰器的属性

3. 属性装饰器

属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、成员的名字。

// 属性装饰器
function logProperty(params:any){
  return function(target:any,attr:any){
    console.log(target);  // 输出  指向的当前类  --> Decoration1
    console.log(attr);  // 输出 指向装饰的属性--> url
    target[attr]=params;
  }
}


class Decoration1 {
  @logProperty("wang")
  public url : string | undefined;

  constructor() {
  }
  getData () {
    console.log(this.url)
  }
}
const d1:any = new Decoration1();
d1.getData();

4. 方法装饰器

方法装饰会在运行时传入下列3个参数:
1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
2、成员的名字。
3、成员的属性描述符。

function get(params: any) {
  return function (target: any, methodName: any, desc: any) {
    console.log(target);  // 装饰器指向的当前类, 里面包含着类型的属性
    console.log(methodName);  // 装饰的方法名
    console.log(desc);  // 输出描述
    /*
     * {
        value: [Function: getData],
        writable: true,
        enumerable: false,
        configurable: true
      }
    * */
    // 往当前类中追加一个方法
    target.baseUrl = "https://github.io";
    // 往当前类中追加一个方法
    target.run = function () {
      console.log("running");
      console.log(this.url);  // 输出 undefined
      console.log(this.base);  // 输出 undefined
      console.log(desc.value);  // 输出 getData方法
    };
    const oldMethod = desc.value;
    // 修改装饰器中的方法, 把getData方法里面传入的参数改为string类型
    desc.value = function (...args:Array<any>) {
      // 遍历形参数组, 将数组中的每一项变为string类型
      args = args.map((value, index, array)=>{
        return String(value);
      });
      // 打印出所有的参数查看结果
      console.log(args);  // 输出 [ '11', '22', '13', '11' ]
      console.log(params);  // 可以正常输出传参内容
      oldMethod.apply(this, args)  // 此时就可以调用原版中的getData方法
    }
    // 但是此时方法已经被装饰器所替换, 想要修改而不是替换, 就需要进行对象冒充

  }
}
function logPrototype(params: any) {
  return function (target: any, attr: any) {
    target[attr] = params;
  }
}

class Decoration1 {
  @logPrototype("https://wangermaizi.github.io")
  public url: string | undefined;
  constructor() {}
  @get("https://wangermaizi.github.io")
  getData() {
    console.log(this.url);  // this.url需要通过属性装饰进行修改, 不能方法装饰器中修改
  }
}
const d1:any = new Decoration1();

5. 参数装饰器

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

​ 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
​ 2、方法的名字。
​ 3、参数在函数参数列表中的索引。

6. 装饰器执行顺序

属性 => 方法 => 方法参数 => 类

如果有多个同样的装饰器,它会先执行后面的

相关文章

网友评论

      本文标题:typescript入门学习

      本文链接:https://www.haomeiwen.com/subject/ycibpktx.html