#置Ts环境
typescript是的超集javascript,相比原生js,规避了动态类型的所产生的诸多问题,以及完善了js对象使用的体验
vscode配置自动编译
-
第一步 tsc --inti 生成tsconfig.json 改 "outDir": "./js",
-
第二步 任务 - 运行任务 监视tsconfig.json
数据类型
布尔类型(boolean)
var flag:boolean=true;// flag='str'; //错误flag=false; //正确
数字类型(number)
var num:number=123;num=456;//num='str'; //错误
字符串类型(string)
var str:string='hei_ts';str='hellow word'; //正确str=true; //错误
数组类型(array)
ts中定义数组有两种方式
下面以Number数据类型规定的数组为例(js数组原则上可以存储任意类型的数据)
1.第一种定义数组的方式
var arr:number[]=[0,2,3];
2.第二种定义数组的方式
var arr:Array<number>=[11,22,33];
元组类型(tuple)
//var arr:Array<number>=[11,22,33];//因为ts中数组类型只提供单类型存储。为了保证原生的特性依旧可以正常使用ts提供了元组类型let arr:[number,string]=[123,'typescript'];console.log(arr);
枚举类型(enum)
随着计算机的不断普及,程序不仅只用于数值计算,还更广泛地用于处理非数值的数据。 例如:性别、月份、星期几、颜色、单位名、学历、职业等,都不是数值数据。 在其它程序设计语言中,一般用一个数值来代表某一状态,这种处理方法不直观,易读性差。 如果能在程序中用自然语言中有相应含义的单词来代表某一状态,则程序就很容易阅读和理解。 也就是说,事先考虑到某一变量可能取的值,尽量用自然语言中含义清楚的单词来表示它的每一个值, 这种方法称为枚举方法,用这种方法定义的类型称枚举类型。
//enum 枚举名{ // 标识符[=整型常数], // 标识符[=整型常数],// 标识符[=整型常数], // } ; enum Color {blue,red=3,'orange'};var c:Color=Color.blue;//如果标识符没有赋值 它的值就是下标console.log(c); //0var c:Color=Color.red;console.log(c); //3 这里的赋值string类型也okvar c:Color=Color.orange;console.log(c); //4
##任意类型(any)
可以赋值任意类型,常常使用在不限制参数类型的方法里
var num:any=123;num='str';num=true;console.log(num)
##null 和 undefined
属于其他(never类型)数据类型的子类型
var num:number;console.log(num) //输出:undefined //报错(未赋值)var num:undefined;console.log(num) //输出:undefined //正确//定义没有赋值就是undefinedvar num:number | undefined;console.log(num);//输出:undefined //正确num=123;console.log(num);//输出:123 //正确var num:null;num=null;console.log(num)//输出:null //正确//一个元素可能是 number类型 可能是null 可能是undefinedvar num:number | null | undefined;num=1234;console.log(num)
##void类型
typescript中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值。
//表示方法没有返回任何类型//正确写法function run():void{ console.log('run')}run();//错误写法undefined/null等never类型不能作为返回类型标记function run():undefined{ console.log('run')}run();
##never类型
never类型:是其他类型 (包括 null 和 undefined)的子类型,代表从不会出现的值。
这意味着声明never的变量只能被never类型所赋值。
如:
var a:undefined;a=undefined;var b:null;b=null;var a:never;//a=123; //错误的写法//真确写法a=(()=>{throw new Error('错误');})()
typeScript中的函数
#函数 ##函数的定义
//es5定义函数的方法//函数声明法function run(){ return 'run';}//匿名函数var run2=function(){ return 'run2';}//ts中定义函数的方法function run():string{ return 'run';}//匿名函数var run=function():number{ return 123;}console.log(run()); /*调用方法*///错误写法function run():string{ return 123;//已经标记了返回类型未string实际返回的是number}//ts中定义方法传参function getInfo(name:string,age:number):string{ return `${name} --- ${age}`;}console.log(getInfo('小姐姐',20));
##可选参数
// es5里面方法的实参和行参可以不一样,但是ts中必须一样,如果不一样就需要配置可选参数 function getInfo(name:string,age?:number):string{ if(age){ return `${name} --- ${age}`; }else{ return `${name} ---年龄保密`; }}console.log(getInfo('小姐姐'))console.log(getInfo('小姐姐',18))//注意:可选参数必须配到参数的最后//错误写法function getInfo(name?:string,age:number):string{ if(age){ return `${name} --- ${age}`; }else{ return `${name} ---年龄保密`; }}
##默认参数
// es5里面没法设置默认参数,es6和ts中都可以设置默认参数function getInfo(name:string,age:number=20):string{ if(age){ return `${name} --- ${age}`; }else{ return `${name} ---年龄保密`; }}console.log( getInfo('小姐姐'));//小姐姐---20console.log( getInfo('小姐姐',19));//小姐姐---19
##剩余参数
//使用扩展运算符 接受新参传过来的值//...result的可以理为将参数装入名为result的数组中function sum(...result:string[]):string{ var sum=0; for(var i=0;i<result.length;i++){ sum+=result[i]; } return sum;}console.log(sum('1','2','3','4','5','6'))//0123456function sum(a:string,b:string,...result:string[]):string{ var sum=0; for(var i=0;i<result.length;i++){ sum+=result[i]; } sum+=a+b return sum;}console.log(sum('1','2','3','4','5','6'))//0345612
##函数重载
// java中方法的重载:重载指的是两个或者两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况。// typescript中的重载:通过为同一个函数提供多个函数类型定义来试下多种功能的目的。//ts为了兼容es5 以及 es6 重载的写法和java中有区别。//es5中出现同名方法,下面的会替换上面的方法 function css(config){}function css(config,value){}//ts中的重载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('帅气的小哥哥')); //正确console.log(getInfo(20)); //正确console.log(getInfo(true)); //错误写法//或function getInfo(name:string):string;function getInfo(name:string,age:number):string;function getInfo(name:any,age?:any):any{ if(age){ return '我是:'+str;+'我的年龄是'+age; }else{ return '我叫:'+name; }}console.log(getInfo('帅气的小哥哥')); //正确console.log(getInfo('帅气的小哥哥',20)); //正确
Ts中的类
es5中的类和继承
// es5里面的类 //1.最简单的类function Person(){ this.name='小姐姐'; this.age=20;}var p=new Person();console.log(p.name);//2、构造函数和原型链里面增加方法function Person(){ this.name='小姐姐'; /*属性*/ this.age=20; this.run=function(){ console.log(this.name+'在运动'); }}//原型链上面的属性会被多个实例共享构造函数不会Person.prototype.sex="女";Person.prototype.work=function(){ console.log(this.name+'在工作');}var p=new Person();console.log(p.name);p.run();p.work();//3类里面的静态方法function Person(){ this.name='小姐姐'; /*属性*/ this.age=20; this.run=function(){ /*实例方法*/ console.log(this.name+'在运动'); }}Person.getInfo=function(){ console.log('我是静态方法');}//调用静态方法Person.getInfo();// 4、es5里面的继承 对象冒充实现继承function Person(){ this.name='小姐姐'; /*属性*/ this.age=20; this.run=function(){ /*实例方法*/ console.log(this.name+'在运动'); }} Person.prototype.sex="女";Person.prototype.work=function(){ console.log(this.name+'在工作');}//Web类 继承Person类function Web(){ Person.call(this); /*对象冒充实现继承*/}var w=new Web();w.run(); //对象冒充可以继承构造函数里面的属性和方法w.work(); //对象冒充可以继承构造函数里面的属性和方法但是没法继承原型链上面的属性和方法// 5、es5里面的继承 原型链实现继承function Person(){ this.name='小姐姐'; /*属性*/ this.age=20; this.run=function(){ /*实例方法*/ console.log(this.name+'在运动'); }} Person.prototype.sex="女";Person.prototype.work=function(){ console.log(this.name+'在工作');}//Web类 继承Person类 原型链+对象冒充的组合继承模式function Web(){}Web.prototype=new Person(); //原型链实现继承var w=new Web();//原型链实现继承:可以继承构造函数里面的属性和方法也可以继承原型链上面的属性和方法w.run();w.work();// 6、 原型链实现继承的问题?function Person(name,age){ this.name=name; /*属性*/ this.age=age; this.run=function(){ /*实例方法*/ console.log(this.name+'在运动'); }} Person.prototype.sex="女";Person.prototype.work=function(){ console.log(this.name+'在工作');}var p=new Person('小姐姐',20);p.run();function Person(name,age){ this.name=name; /*属性*/ this.age=age; this.run=function(){ /*实例方法*/ console.log(this.name+'在运动'); }} Person.prototype.sex="女";Person.prototype.work=function(){ console.log(this.name+'在工作');}function Web(name,age){}Web.prototype=new Person();var w=new Web('月儿',20); //实例化子类的时候没法给父类传参w.run();var w1=new Web('青鸾',22);w1.run();//7.原型链+对象冒充的组合继承模式(这里的冒充指的是改变this指向让this指向Person)function Person(name,age){ this.name=name; //属性 this.age=age; this.run=function(){ //实例方法 console.log(this.name+'在运动'); }} Person.prototype.sex="女";Person.prototype.work=function(){ console.log(this.name+'在工作');}function Web(name,age){ Person.call(this,name,age); //对象冒充继承实例化子类可以给父类传参}Web.prototype=new Person();var w=new Web('青鸾',20); //实例化子类的时候没法给父类传参w.run();w.work();var w1=new Web('月儿',21);w1.run();w1.work();//8、原型链+对象冒充继承的另一种方式function Person(name,age){ this.name=name; /*属性*/ this.age=age; this.run=function(){ /*实例方法*/ console.log(this.name+'在运动'); }} Person.prototype.sex="女";Person.prototype.work=function(){ console.log(this.name+'在工作');}function Web(name,age){ Person.call(this,name,age); //对象冒充继承 可以继承构造函数里面的属性和方法、实例化子类可以给父类传参}Web.prototype=Person.prototype;var w=new Web('青鸾',20); //实例化子类的时候没法给父类传参w.run();w.work();
##Ts中的类
class Person{ name:string; //属性 前面省略了public关键词 constructor(n:string){ //构造函数 实例化类的时候触发的方法 this.name=n; } run():void{ console.log(this.name); }}var p=new Person('青鸾');p.run()
###类的定义
class Person{ name:string; constructor(name:string){ //构造函数实例化类的时候触发的方法 this.name=name; } getName():string{ return this.name; } setName(name:string):void{ this.name=name; }}var p=new Person('青鸾');console.log(p.getName());
继承
ts中实现继承 extends、 super
class Person{ name:string; constructor(name:string){ this.name=name; } run():string{ return `${this.name}在运动` }}var p=new Person('青鸾');console.log(p.run())class Web extends Person{ constructor(name:string){ super(name); /*初始化父类的构造函数*/ }}var w=new Web('青鸾');console.log(w.run());//ts中继承的探讨 父类的方法和子类的方法一致class Person{ name:string; constructor(name:string){ this.name=name; } run():string{ return `${this.name}在运动` }}var p=new Person('青鸾');console.log(p.run())class Web extends Person{ constructor(name:string){ super(name); /*初始化父类的构造函数*/ } run():string{ return `${this.name}在运动-子类` } work(){ alert(`${this.name}在工作`) }}var w=new Web('青鸾');console.log(w.run());//青鸾在运动-子类w.work();console.log(w.run());
类里面的修饰符
类里面的修饰符 typescript里面定义属性的时候给我们提供了 三种修饰符
-
public :公有 在当前类里面、 子类 、类外面都可以访问
-
protected:保护类型 在当前类里面、子类里面可以访问 ,在类外部没法访问
-
private :私有 在当前类里面可以访问,子类、类外部都没法访问
属性如果不加修饰符 默认就是 公有 (public)
###静态属性、静态方法
使用static修饰符修饰静态属性方法(这里的静态是指不用new,可以直接通过类名调用的方法)
//es5中的静态方法function Person(){ this.run1=function(){ }}Person.name='哈哈哈';Person.run2=function(){ //静态方法}var p=new Person();Person.run2(); //静态方法的调用//ts中的静态方法class Per{ public name:string; public age:number=20; //静态属性 static sex="女"; constructor(name:string) { this.name=name; } run(){ //实例方法 console.log(`${this.name}在运动`) } work(){ console.log(`${this.name}在工作`) } static print(){ //静态方法 里面没法直接调用类里面的属性 console.log('print方法'+Per.sex); }}var p=new Per('青鸾');p.run();Per.print();console.log(Per.sex);
抽象类 继承 多态
//多态:父类定义一个方法不去实现,让继承它的子类去实现 每一个子类有不同的表现//多态属于继承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+'吃咸鱼' }}
typescript中的抽象类:
-
它是提供其他类继承的基类,不能直接被实例化。 用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。
-
abstract抽象方法只能放在抽象类里面
-
抽象类和抽象方法用来定义标准
//Animal 这个类要求它的子类必须包含eat方法//标准: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('傻fuifui');d.eat();class Cat extends Animal{ //抽象类的子类必须实现抽象类里面的抽象方法 constructor(name:any){ super(name) } run(){} eat(){ console.log(this.name+'吃咸鱼') }}var c=new Cat('745');c.eat();
#typeScript中的接口 接口的作用:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面,接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据,也不关心这些类里方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。 typescrip中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等。
数白了就是定义数据结构(定义标准)
##属性类接口
对json的约束
interface FullName{ firstName:string; //注意以;结束 secondName:string;}function printName(name:FullName){ // 必须传入对象 firstName secondName console.log(name.firstName+'--'+name.secondName);}function printInfo(info: FullName) { // 必须传入对象 firstName secondName console.log(info.firstName + info.secondName);}// printName('1213'); //错误var obj={ //传入的参数必须包含 firstName secondName age:20,//多了可以少了不行 firstName:'青', secondName:'鸾'};printInfo({ firstName: '悦', secondName: '儿'})//接口 :可选属性interface FullName { firstName: string; secondName?: string;}function getName(name: FullName) { console.log(name)}getName({ firstName: 'firstName'})//参数的顺序可以不一样getName({ secondName: 'secondName', firstName: 'firstName'})
##函数类型接口
对方法传入的参数 以及返回值进行约束 批量约束可索引接口
// 加密的函数类型接口interface encrypt{ (key:string,value:string):string;}var md5:encrypt=function(key:string,value:string):string{ //模拟操作加密 return key+value;}console.log(md5('name','zhangsan'));var sha1:encrypt=function(key:string,value:string):string{ //模拟操作加密 return key+'----'+value;}console.log(sha1('name','lisi'));
##类类型接口
类类型接口:对类的约束和抽象类抽象有点相似
interface Animal{ name:string; eat(str:string):void;}class Dog implements Animal{//用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('老鼠');
##接口扩展
接口扩展:接口可以继承接口
interface Animal{ eat():void;}interface Person extends Animal{ work():void;}class Programmer{ public name:string; constructor(name:string){ this.name=name; } coding(code:string){ console.log(this.name+code) }}class Web extends Programmer implements Person{ constructor(name:string){ super(name) } eat(){ console.log(this.name+'喜欢吃馒头') } work(){ console.log(this.name+'写代码'); }}var w=new Web('小姐姐');w.eat();w.coding('写ts代码');
泛型
##泛型的定义
泛型:软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑可重用性。 组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,这在创建大型系统时为你提供了十分灵活的功能。
在像C#和Java这样的语言中,可以使用泛型来创建可重用的组件,一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。
通俗理解:泛型就是解决 类 接口方法的复用性、以及对不特定数据类型的支持(类型校验)
泛型:可以支持不特定的数据类型 //要求:传入的参数和返回的参数一致
//只能返回string类型的数据function getData(value:string):string{ return value;}//同时返回 string类型 和number类型 (代码冗余)function getData1(value:string):string{ return value;}function getData2(value:number):number{ return value;}//同时返回 string类型 和number类型 any可以解决这个问题function getData(value:any):any{ return '哈哈哈';}getData(123);getData('str');//any放弃了类型检查,传入什么 返回什么。比如:传入number 类型必须返回number类型 传入 string类型必须返回string类型//传入的参数类型和返回的参数类型可以不一致function getData(value:any):any{ return '哈哈哈';}//这个时候就用到了泛型
##泛型函数
//泛型:可以支持不特定的数据类型 //要求:传入的参数和返回的参数一直// T表示泛型,具体什么类型是调用这个方法的时候决定的function getData<T>(value:T):T{ return value;}getData<number>(123);getData<string>('1214231');getData<number>('2112'); /*错误的写法*/ //function getData<T>(value:T):any{//泛型可以选配// return '2145214214';//}getData<number>(123); //参数必须是numbergetData<string>('这是一个泛型');
##泛型类
// 泛型类:比如有个最小堆算法,需要同时支持返回数字和字符串 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);console.log(m.min());//3//类的泛型class MinClas<T>{ public list: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; }}var m1=new MinClas<number>(); /*实例化类 并且制定了类的T代表的类型是number*/m1.add(11);m1.add(3);m1.add(2);alert(m1.min())var m2=new MinClas<string>(); /*实例化类 并且制定了类的T代表的类型是string*/m2.add('c');m2.add('a');m2.add('v');alert(m2.min())
##泛型接口
//函数类型接口interface ConfigFn{ (value1:string,value2:string):string;}var setData:ConfigFn= function(value1:string,value2:string):string{ return value1+value2; }setData('name','张三');//1、泛型接口interface ConfigFn{ <T>(value:T):T;}var getData:ConfigFn=function<T>(value:T):T{ return value;}getData<string>('小姐姐');getData<string>(1243); //错误//2、泛型接口(喜欢这种不会扰乱理解)interface ConfigFn<T>{ (value:T):T;}function getData<T>(value:T):T{ return value;}var myGetData:ConfigFn<string>=getData; myGetData('20'); /*正确*/myGetData(20) //错误
#命名空间
命名空间:
-
在代码量较大的情况下,为了避免各种变量命名相冲突,可将相似功能的函数、类、接口等放置到命名空间内
-
同Java的包、.Net的命名空间一样,TypeScript的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。命名空间内的对象通过export关键字对外暴露。
命名空间和模块的区别:
-
命名空间:内部模块,主要用于组织代码,避免命名冲突。
-
模 块:ts的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间。
modules文件夹下的animal:
export namespace A{ interface Animal { name: string; eat(): void; } export class Dog implements Animal { name: string; constructor(theName: string) { this.name = theName; } eat() { console.log(`${this.name} 在吃狗粮。`); } } export class Cat implements Animal { name: string; constructor(theName: string) { this.name = theName; } eat() { console.log(`${this.name} 吃猫粮。`); } } } export namespace B{ interface Animal { name: string; eat(): void; } export class Dog implements Animal { name: string; constructor(theName: string) { this.name = theName; } eat() { console.log(`${this.name} 在吃狗粮。`); } } export class Cat implements Animal { name: string; constructor(theName: string) { this.name = theName; } eat() { console.log(`${this.name} 在吃猫粮。`); } } }
引用者
import {A,B} from './modules/animal';var d=new A.Dog('小黑');//通过暴露的命名空间名点暴露的类/方法进行调用(模块话开发的话,如果是单文件就不用export修饰同时不用import引入,直接调用命名空间名点空间内的类/方法即可调用)d.eat();var dog=new B.Dog('小花');dog.eat();
装饰器
装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为。
通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。
常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器
装饰器的写法:普通装饰器(无法传参) 、 装饰器工厂(可传参)
装饰器是过去几年中js最大的成就之一,已是Es7的标准特性之一
##类装饰器
类装饰器在类声明之前被声明(紧靠着类声明)。 类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。 传入一个参数
//类装饰器:普通装饰器(无法传参)function logClass(params:any){ console.log(params); // params 就是当前类 params.prototype.apiUrl='动态扩展的属性'; params.prototype.run=function(){ console.log('我是一个run方法'); }}@logClassclass HttpClient{ constructor(){} getData(){}}var http:any=new HttpClient();console.log(http.apiUrl); //动态扩展的属性http.run(); //我是一个run方法//类装饰器:装饰器工厂(可传参)function logClass(params:string){ return function(target:any){ console.log(target);//就是当前类(这个代码中指HttpClient) console.log(params);//传入的http://www.itying.com/api target.prototype.apiUrl=params; }}@logClass('http://www.itying.com/api')class HttpClient{ constructor(){} getData(){}}var http:any=new HttpClient();console.log(http.apiUrl);//http://www.itying.com/api//下面是一个重载构造函数的例子。//类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。//如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。function logClass(target:any){ console.log(target); return class extends target{ apiUrl:any='我是修改后的数据'; getData(){ this.apiUrl=this.apiUrl+'----'; console.log(this.apiUrl); } }}@logClassclass HttpClient{ public apiUrl:string | undefined; constructor(){ this.apiUrl='我是构造函数里面的apiUrl'; } getData(){ console.log(this.apiUrl); }}var http=new HttpClient();http.getData();//我是修改后的数据----
##属性装饰器
属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
-
对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
-
成员的名字。
//类装饰器function logClass(params:string){ return function(target:any){ // console.log(target); // console.log(params); }}//属性装饰器//params 传入参数 这里是指 itying.com//target 就是当前修饰的类 这里是指 HttpClient//attr 当前装饰的属性名 这里是指 urlfunction logProperty(params:any){ return function(target:any,attr:any){ console.log(target); console.log(attr); target[attr]=params;//在属性装饰器中target[attr]属性可以中这样的方式操作 }}@logClass('xxxx')class HttpClient{ @logProperty('http://itying.com') public url:any |undefined;//当前装饰的属性 constructor(){ } getData(){ console.log(this.url); }}var http=new HttpClient();http.getData();
##方法装饰器
它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰会在运行时传入下列3个参数:
-
对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
-
成员的名字。
-
成员的属性描述符。
//方法装饰器一//target=HttpClient { getData: [Function] }//target=HttpClient类//methodName=getData//方法名//desc=对于方法的说明//{//"writable":true, //可写//"enumerable":true, //可枚举//"configurable":true //可配置//}////params='http://www.itying,com'function get(params:any){ return function(target:any,methodName:any,desc:any){ console.log(target); console.log(methodName); console.log(desc); target.apiUrl='xxxx'; target.run=function(){ console.log('run'); } }}class HttpClient{ public url:any |undefined; constructor(){ } @get('http://www.itying,com') getData(){ console.log(this.url); }}var http:any=new HttpClient();console.log(http.apiUrl);//xxxxhttp.run(); //run//方法装饰器二function get(params:any){return function(target:any,methodName:any,desc:any){ console.log(target); console.log(methodName); console.log(desc.value);//desc.value是目前HttpClient里的getData方法 //修改装饰器的方法把装饰器方法里面传入的所有参数改为string类型 //1、保存当前的方法 var oMethod=desc.value; //2、重写 desc.value=function(...args:any[]){ args=args.map((value)=>{ return String(value); }) //然后使用this指针重定向的方法执行未修改的方法 oMethod.apply(this,args); } }}class HttpClient{ public url:any |undefined; constructor(){ } @get('http://www.itying,com') getData(...args:any[]){ console.log(args); console.log('我是getData里面的方法'); }}var http=new HttpClient();http.getData(123,'xxx');//["123", "xxx"]//我是getData里面的方法
##参数装饰器
参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据 ,传入下列3个参数:
-
对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
-
方法的名字。
-
参数在函数参数列表中的索引。
function logParams(params:any){ return function(target:any,methodName:any,paramsIndex:any){ console.log(params);//xxxxx console.log(target);//当前对象 console.log(methodName);//getData函数名 console.log(paramsIndex);//参数索引 target.apiUrl=params; } }class HttpClient{ public url:any |undefined; constructor(){ } getData(@logParams('xxxxx') uuid:any){ console.log(uuid); }}var http:any = new HttpClient();http.getData(123456);//123456console.log( http.apiUrl);//xxxxx
##装饰器执行顺序
属性=>方法=>方法参数=>类
如果有多个同样的装饰器,它会先执行后面的
//验证代码function logClass1(params:string){ return function(target:any){ console.log('类装饰器1') }}function logClass2(params:string){ return function(target:any){ console.log('类装饰器2') }}function logAttribute1(params?:string){ return function(target:any,attrName:any){ console.log('属性装饰器1') }}function logAttribute2(params?:string){ return function(target:any,attrName:any){ console.log('属性装饰器2') }}function logMethod1(params?:string){ return function(target:any,attrName:any,desc:any){ console.log('方法装饰器1') }}function logMethod2(params?:string){ return function(target:any,attrName:any,desc:any){ console.log('方法装饰器2') }}function logParams1(params?:string){ return function(target:any,attrName:any,desc:any){ console.log('方法参数装饰器1') }}function logParams2(params?:string){ return function(target:any,attrName:any,desc:any){ console.log('方法参数装饰器2') }}@logClass1('http://www.itying.com/api')@logClass2('xxxx')class HttpClient{ @logAttribute1() @logAttribute2() public apiUrl:string | undefined; constructor(){ } @logMethod1() @logMethod2() getData(){ return true; } setData(@logParams1() attr1:any,@logParams2() attr2:any,){ }}var http:any=new HttpClient();
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!