Typescript

Typescript 安装 编译

在使用npm命令之前电脑必须安装 nodejs
安装

npm install -g typescript
或者
cnpm install -g typescript
或者
yarn global add typescript

运行:

tsc helloworld.ts

注意:如果电脑上面没有安装过cnpm,请先安装cnpm:

npm install -g cnpm --registry=https://registry.npm.taobao.org

注意:如果电脑上面没有安装过yarn请先安装yarn:

npm install -g yarn
或者
cnpm install -g yarn

Typescript 开发工具 Vscode 自动编译.ts文件

  • 创建 tsconfig.json 文件 tsc --init 生成配置文件
  • 然后打开该文件,解开一行注释 “outDir”:"./js"

Typescript中的数据类型

typescript中为了使编写的代码更规范,更有利于维护,增加了类型校验

  • 布尔类型(boolean)
  • 数字类型(number)
  • 字符串类型(string)
  • 数组类型(array)
  • 元组类型(tuple)
  • 枚举类型(enum)
  • 任意类型(any)
  • null和undefined
  • void类型
  • never类型
//布尔
let flag:boolean=false
//数字
let age:number=5
//字符串
let name:string="zhangsan"
//数组
let arr:number[]=[1,2,2,5,6]
let arr:string[]=["php","jsva"]
或者
let arr:Array<number>=[1,5,6,8,9]
let arr:Array<string>=["php","jsva"],
//元组类型数组的一种
let arr:[string,number,boolean]=["java",1,true]
//枚举类型(enum)
//随着计算机的不断普及,程序不仅只用于数值计算,还更广泛地用于处理非数值的数据,例如:性别、月份、星期几、颜色、单位名、学历、职业等,都不是数值数据。
//在其他程序设计语言中,一般用一个数值来代表某一状态,这种处理方法不直观,易读性差。如果能在程序中用自然语言中有相应含义的单词来代表某一状态,则程序就很容易阅读和理解。
//也就是说,事先考虑到某一变量可能取的值,尽量用自然语言中含义清楚的单词来表示它的每一个值,
//这种方法称为枚举方法,用这种方法定义的类型称枚举类型。
/*enum 枚举名{
	标识符[=整型常数],
	标识符[=整型常数],
	...
	标识符[=整型常数],
}
pay_status 0未支付 1支付 2交易成功
flag 1表示true -1表示false*/
如下:
enum Flag {success=1,error=-1}
let f:Flag=Flag.success
//any任意类型
let oBox:any=document.getElementById('box')
oBox.style.color='red'
//null和undefind 其他(never类型) 数据类型的子类型
//定义没有赋值就是undefined
let num:number|undefined;
let num:null,
let num:null|undefined|number;
//void类型:typescript中的void表示没有任何类型,一般用于定义方法的时候方法没有返回值
function run:void(){
	console.log('run')
}
//never类型:是其他类型 (包括null 和undefined)的子类型,代表从不会出现的值。这意味着声明never的变量只能被never类型所赋值。
let a:never;
//a=123错误写法
a=(()=>{
	throw new Error('错误')
})

ts中定义函数的方法

 //函数声明法
 function run:string{
	return 'run'
 }
 //错误写法  定义返回string类型却返回数值类型
  function run:string{
	return 123
 }
 //匿名函数
 let fun2=function():number{
	return 123
 }
 //ts中定义方法传参
 function getInfo(name:string,age:number):string{
	return `${name}----${age}`
 }
 alert(getInfo('张三',20))
 //可选参数
//es5里面方法的实参和行参可以不一样,但是ts中必须一样,如果不一样就需要配置可选参数
function getInfo(name:string,age?:number){
	if(age){
		return `${name}---${age}`
	}else{
		return `${name}---年龄保密`
	}
}
alert(getInfo('张三',123))
alert(getInfo('张三'))
//注意:可选参数必须配置到参数的最后面

//默认参数
//es5里面没法设置默认参数,es6和ts中都可以设置默认参数
function getInfo(name:string,age:number=20):string{
	if(age){
		return `${name}---${age}`
	}else{
		return `${name}---年龄保密`
	}
}
alert(getInfo('张三'))

//剩余参数
//三点运算符 接收形参传过来的值
function sum(...result:number[]:number){
	let sum =0;
	for(let i =0;i<result.length;i++){
		sum+result[i];
	}
	return sum
}
alert(sum(1,2,3,4))

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

//es5中出现同名方法,下面的会替换上面的方法

//ts中的重载
function getInfo(name:string):string;
function getInfo(age:number):number;
function getInfo(str:any):any{
	if(typof str==='string'){
		return '我叫:'+str
	}else{
		return '我的年龄是'+str
	}
}
alert(getInfo('张三'))
alert(getInfo(20))

es5里面的类

//1.最简单的类
function Person(){
	this.name="张三";
	this.age=20;
}
let p=new Person();
alert(p.name);

//2.构造函数和原型链里面增加方法
function Person(){
	this.name="张三";//属性
	this.age=20this.run=function(){
		alert(this.name+'在运动')
	}
}
//原型链上的属性会被多个实例共享  构造函数不会
Person.prototype.sex="男";
Person.prototype.work=function(){
	alert(this.name+'在吃饭')
}

let p =new Person();
alert(p.name);
p.run();
p.work();


//3.类里面的静态方法
function Person(){
	this.name="张三";//属性
	this.age=20this.run=function(){
		alert(this.name+'在运动')
	}
}

Person.getInfo=function(){
	alert('我是静态方法')
}
//原型链上的属性会被多个实例共享  构造函数不会
Person.prototype.sex="男";
Person.prototype.work=function(){
	alert(this.name+'在吃饭')
}

let p =new Person();
alert(p.name);
p.run();
p.work();

//调用静态方法
Person.getInfo()


//4.es5里面的继承
function Person(){
	this.name='张三';
	this.age=20;
	this.run=function(){//实例方法
		alert(this.name+'在运动')
	}
}
Person.prototype.sex="男“;
Person.prototype.work=function(){
	alert(this.name+'在工作')
}

//web类继承Person类 原型链加对象冒充的组合继承
function Web(){
	Person.call(this); //对象冒充实现继承
}
let w=new Web();
w.run();//对象冒充可以继承构造函数里面的属性和方法
w.work();//但是没法继承原型链上面的属性和方法

//5.es5里面的继承  原型链实现继承
function Person(){
	this.name='张三';
	this.age=10this.run=function(){
		alert(this.name+'在活动')
	}
}
Person.prototype.sex='男';
Person.prototype.work=function(){
	alert(this.name+'在工作')
}
//Web类 继承Person类 原型链+对象冒充的组合继承模式
function Web(){
	
}
Web.prototype=new Person();//原型链实现继承
let w=new Web();
//原型链实现继承:可以继承构造函数里面的属性和方法 也可以继承原型链上面的属性和方法
w.run();
w.work();

//6.原型链继承的问题
function Person(){
	this.name='张三';
	this.age=10this.run=function(){
		alert(this.name+'在活动')
	}
}
Person.prototype.sex='男';
Person.prototype.work=function(){
	alert(this.name+'在工作')
}
//let p=new Person('李四',20);
//p.run();
function Web=function(name,age){
	Person.call(this,name,age)//对象冒充继承 实例化字类可以给父类传参
};
Web.prototype=new Person();
let w=new Web('赵四',20);//实例化子类的时候没法给父类传参
w.run();
let w1=new Web('王五',22);

//7.原型链+对象冒充继承的另一种
function Person(){
	this.name='张三';
	this.age=10this.run=function(){
		alert(this.name+'在活动')
	}
}
Person.prototype.sex='男';
Person.prototype.work=function(){
	alert(this.name+'在工作')
}
//let p=new Person('李四',20);
//p.run();
function Web=function(name,age){
	Person.call(this,name,age)//对象冒充继承 实例化字类可以给父类传参
};
Web.prototype=Person.prototype;
let w=new Web('赵四',20);//实例化子类的时候没法给父类传参
w.run();
let w1=new Web('王五',22);

ts中的类

//1.ts中的类
class Person{
	name:string;//属性 前面省略了public关键词
	constructor(n:string){//构造函数  实例化类的时候触发的方法
		this.name=n
	}
	run():void{
		alert(this.name)
	}
}
let p=new Person('张三');
p.run()


//

class Person{
	name:string;//属性 前面省略了public关键词
	constructor(name:string){//构造函数  实例化类的时候触发的方法
		this.name=name
	}
	getName():string{
		return this.name
	}
	setName(name:string):void{
		this.name=name
	}
}
let p=new Person('张三');
alert(p.getName());
p.setName('赵四');
alert(p.getName());

//2.ts中实现继承  extends、super
class Person{
	name:string;
	constructor(name:string){
		this.name:name;
	}
	run():string{
		return `${this.name}在运动`
	}
}
//let p= new Person('刘能');
//alert(p.run());

class Web extends Person{
	constructor(name:string){
		super(name);//初始化父类的构造函数
	}
	run():string{
		return `${this.name}+在运动-字类`
	}
	work(){
		alert(`${this.name}在工作`)
	}
}
let w=new Web('李四');
//alert(w.run());
//w.work();
alert(w.run())
//如果子类有和父类同名的方法,优先调用子类自身的

//3.类里面的修饰符 typescript里面定义属性的时候给我们提供了 三种修饰符

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


//类外面访问公有属性
class Person{
	public name:string;//公有属性
	constructor(name:string){
		this.name:name;
	}
	run():string{
		return `${this.name}在运动`
	}
}
//let p= new Person('刘能');
//alert(p.name);


//类外部没法访问保护类型的属性
class Person{
	protected name:string;//保护类型
	constructor(name:string){
		this.name:name;
	}
	run():string{
		return `${this.name}在运动`
	}
}
//let p= new Person('刘能');
//alert(p.name);//报错


// ts中的静态类型 静态方法
class Person{
	public name:string
	constructor(name:string){
		this.name=name
	}
	run(){//实例方法
		alert(`${this.name}在运动`)
	}
	work(){
		alert(`${this.name}在工作`)
	}
	static print(){//静态方法
		alert('print方法')
	}
}
let p= new Person('张丹');
p.run();


//

class Person{
	static food?:string //静态属性
	public name:string
	public age:number
	constructor(name:string){
		this.name=name
	}
	run(){//实例方法
		alert(`${this.name}在运动`)
	}
	work(){
		alert(`${this.name}在工作`)
	}
	static print(){//静态方法  里面没法直接调用类里面的属性
		alert('print方法'+this.age)//报错
	}
}
let p= new Person('张丹');
p.run();


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

//多态属于继承
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;
}
//let a=new Animal()/*错误的写法*/

class Dog extends Animal{
	//抽象类的子类必须实现抽象类里面的抽象方法
	constructor(name:any){
		super(name)
	}
	eat(){
		console.log(`${this.name}吃粮食`)
	}
}
let d= new Dog('小狗')

class Cat extends Animal{
	//抽象类的子类必须实现抽象类里面的抽象方法
	constructor(name:any){
		super(name)
	}
	run(){
		console.log(`${this.name}在运动`)
	}
	eat(){
		console.log(`${this.name}吃粮食`)
	}
}
let c= new Cat('小猫')

ts中的接口

// 1.1 属性接口
// 1.2 函数类型接口
// 1.3 可索引接口
// 1.4 类类型接口
// 1.5 接口扩展
/*
接口的作用,在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,
在程序设计里面接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范,接口不关心这些类的内部状态数据
,也不关心这些类里面方法的实现细节,它只规定这批类里必须提供某些方法,提供这些方法的类就可以满足实际需要。
typescript中的接口类似于java,同时还增加了更灵活的接口类型,包括属性、函数、可索引和类等
*/

//1 属性接口  对json的约束
//ts中定义方法
/*
	function printLabel();void{
		console.log('printLabel')
	}
	printLabel()
*/

/*ts中定义方法传入参数
function printLabel(label:string):void{
   console.log('printLabel')			
}
printLabel('hahah')
*/

/*
ts中自定义方法传入参数对 json进行约束

*/
function printLabel(labelledObj:{label:string}){
	console.log(labelledObj.label);
}
let myObj={size:10,label:"Size 10 object"};
printLable(myObj)

//就是传入对象的约束  属性接口
interface FullName{
	firstName:string;//注意约束
	secondName:string;
}
function printName(name:FullName){
	//必须传入对象 firstrName  secondName
	console.log(name.firstName+'--'+name.secondName)
}

function printInfo(info:FullName){
	//必须传入对象 firstrName  secondName
	console.log(name.firstName+'--'+name.secondName)
}
let obj={//传入的参数必须包含 firstName secondName
	age:20,
	firstName:'张',
	secondName:'三'
}
printName(obj);
printInfo({
	firstName:'张',
	secondName:'三'
})


//接口可选属性
interface FullName{
	firstName:string;
	secondName:string;
}
function getName(name:FullName){
	console.log(name)
}
//参数的顺序可以不一样
getName({
	secondName:'三'
	firstName:'张'})


interface FullName{
	firstName:string;
	secondName?:string;
}
function getName(name:FullName){
	console.log(name)
}
//参数的顺序可以不一样
getName({
	firstName:'张'})

//ajax示例

interface Config{
	type:string;
	url:string;
	data?:string;
	datatype:string;
}
//原生js封装的ajax
function ajax(config:Config){
	let xhr= new XMLHttpRequest();
	xhr.open(confi.type,config.url,true);
	xhr.send(config.data);
	xhr.onreadystatechange=function(){
		if(xhr.readyState==4&&xhr.status==200){
			console.log('成功‘)
			if(config.datatype=='json'){
				console.log(JSON.parse(xhr.responseText))
			}else{
				console.log(xhr.responseText)
			}
		}
	}
}
ajax({
	type:'get',
	data:'namezhangsan',
	url:'http:baidu.com',
	datatype:'json'
})
//函数类型接口:对方法传入的参数 以及返回值进行约束  批量约束

//加密的函数类型接口

interface encrypt{
	(key:string,value:string):string;
}

let md5=encrypt=function(key:string,value:string):string{
		//模拟操作
		return key+value
}
console.log(md5('name','zhangsan'))


let shar1:encrypt=function(key:string,value):string{
		//模拟操作
		return key+'----'+value
}
console.log(shar1('name','zhangsan'))


/*
接口的作用,在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范,在程序设计里面接口  
定义标准
*/
//可索引接口,数组,对象的约束 (不常用)
let arr=number[]=[2342,2555]
let arr1:Array<string>=['12','55']

interface UserArr{
	[index:number]:string
}
let arr3:UserArr=['aaa','bbb']
console.log(arr3[0])

interface UserObj{
	[index:string]:string
}
let arr:UserObj=[name:'20',age:20]


//类类型接口:对类的约束 和抽象类有点相似
iterface Animal{
	name:string;
	eat(str:string):void;
}
class Dog implements Animal{
	name:string;
	constructor(name:string){
		this.name=name
	}
	eat(){
		console.log(this.name+'吃骨头')
	}
}

//

interface Animal{
	eat():void;
}

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(){}
}
//接口扩展,接口可以继承接口

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

typescript中的泛型

/*
1.1 泛型的定义
1.2 泛型函数
1.3 泛型类
1.4 泛型接口
*/

/*
泛型,在软件工程中,我们不仅要创建一致的定义良好的API,同时也要考虑
可重用性。组件不仅能够支持当前的数据类型,同时也能支持未来的数据类型,
这在创建大型系统时为你提供了十分灵活的功能。

在像c#和java这样的语言中,可以使用泛型来创建可重用的组件,一个组件
可以支持多种类型的数据,这样用户就可以以自己的数据类型来使用组件。

通俗理解,泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持。
*/

//泛型:可以支持不特定的数据类型 要求:传入的参数和返回的参数一致

```typescript
//T表示泛型,具体什么类型是调用这个方法的时候决定的
function getData<T>(value:T):T{
	return value
}
//getData<number>(123);
getData<string>('124155');

//比如有个最小堆算法 需要同时支持返回数字和字符串两种类型,通过类的泛型来实现。

class MinClass<T>{
	public list:T[]=[];
	add(value: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 m=new MinClass<number>();//实例化类 并且制定了类的T 代表的类型是number
m.add(3)
m.add(33)
m.add(10)
m.add(1)
alert(m.min())
let m2=new MinClass<string>();//实例化类 并且制定了类的T 代表的类型是string
m2.add('2')
m2.add('33')
m2.add('10')
m2.add('1')
alert(m2.min())



/*
定义一个User的类这个类的作用就是映射数据库字段,然后定义
一个 MysqlDb的类这个类用于操作数据库然后把User类作为参数传入到MysqlDb中

let user=new User({
	username:'张三',
	password:'123456'
})
let Db=new MysqlDb();
Db.add(user);

*/
//把类作为参数来约束数据传入的类型
class User{
	username:string|undefined;
	pasword:string|undefind;
}

class MysqlDb{
	add(user:user):boolean{
		console.log(user);
		return true;
	}
}
let u=new User();
u.username='张三';
u,pasword='123456';
let Db=new MysqlDb();
Db.add(u);

//
class AtricleCate{
	title:string|undefined;
	desc:string|undefined;
	status:number|undefined;
}

class MysqlDb{
	add(info:AtricleCate):boolean{
	 	console.log(info);
	 	return true;
	}
}
let a=new ArticleCate();
a.title="国内";
a.desc="国内新闻";
a.status=1;
let Db=new MysqlDb();
Db.add(a);



//操作数据库泛型类
class MysqlDb<T>{
	add(info:T):boolean{
		console.log(info);
		return true;
	}
}

//想给User表增加数据
//1.定义一个User类和数据库进行映射
class User{
	usrname:string|undefined;
	pasword:string|undefined;
}
let u=new User();
u.username='张三';
u.pasword='123';
let Db=new MysqlDb<User>();
Db.add(u);


class ArticlaCate{
	title:string|undefined;
	desc:string|undefined;
	status:number|undefined;
	constructor(params:{
		title:string|undefined;
		desc:string|undefined;
		status?:number|undefined;
	}){
		this.title=params.title;
		this.desc=params.desc;
		this.status=params.status;
	}
	
}
//增加操作
let a=new ArticleCate({
	title:'分类',
	desc:'111',
	status:1
})

//类当作参数的泛型类
let Db=new MysqlDb<ArticleCate>();
Db.add(a)



//操作数据库的泛型类
class MysqlDb<T>{
	add(info:T){
		console.log(info);
		return true;
	}
	updated(info:T,id:number):boolean{
		console.log(info);
		console.log(id);
		return true;
	}
}


例子

功能:定义一个操作数据库的库,支持Mysql Mssql MongoDb
要求:Mysql MsSql MongoDb功能一样,都有 add update delete get 方法
注意:约束统一的规范、以及代码重用
解决方案:需要约束规范所以定义接口,需要代码重用所以用到泛型
1、接口:在面向对象的编程中,接口是一种规范的定义,它定义了行为和动作的规范
2、泛型 通俗理解:泛型就是解决 类 接口 方法的复用性

interface DBI<T>{
	add(info:T):boolean;
	undate(info:T,id:number):boolean;
	delete(id:number):boolean;
	get(id:number):any[];
}

//定义一个操作mysql数据库的类 注意:要实现泛型接口 这个类也应该是一个泛型类
class MysqlDb<T> implements DBI<T>{
	add(info:T):boolean{
		throw new Error("Method not implemented.")
	}
	undate(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[]{
		throw new Error("Method not implemented.")
	}
}

//定义一个操作mssql数据库的类
class MsSqlDb implements DBI<T>{
	constructor(){
		console.log("数据库建立连接")
	}
	add(info:T):boolean{
		console.log(info)
		return true
	}
	undate(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:'李瑁瑁',
				desc:'描述111'
			}{
				title:'白狗',
				desc:'描述222'
			}
		]
		return list
	}
}
//操作用户类 定义一个User类和数据表做映射
class User{
	username:string|undefined;
	password:string|undefined;
}

let u =new User();
u.username="张三1"
u.password="123321"

let oMssql=new MsSqlDb<User>();
oMssql.add(u)

//获取User表 ID=4的数据
let data=oMssql.get(4)
console.log(data)

模块

模块的概念(官方):
关于术语的一点说明:请务必注意一点,TypeScript 1.5里术语名已经发生了变化。“内部模块”现在称为“命名空间”。
“外部模块”现在称为“模块”模块在其自身的作用域里执行,而不是全局作用域里。
这意味着定义在一个模块里的变量,函数,类,接口等的时候,你必须要导入它们,可以使用import形式之一。
模块的概念(总结):
我们可以把一些公共的功能单独抽离成一个文件作为一个模块。
模块里面的变量 函数 类等默认是私有的,如果我们要在外部访问模块里面的数据(变量、函数、类)
我们需要通过export暴露模块里面的数据(变量、函数、类。。。)
暴露后我们通过 import 引入模块就可以使用模块里面暴露的数据(变量、函数、类。。。)

命名空间

在代码量较大的情况下,为了避免各种变量命名冲突,可将相似功能的函数、类、接口放置到命名空间内
同JAVA的包、.net的命名空间一样,TypeScript的命名空间可以将代码包裹起来,只对外暴露需要在外部访问的对象。命名空间内的对象通过export暴露

命名空间和模块的区别
命名空间:内部模块。主要用于组织代码,避免命名冲突
模 块:ts的外部模块简称,侧重代码的复用,一个模块里可能会有多个命名空间。

namespace A{

...
}
namespace B{
   export baseurl
...
}

装饰器

装饰器是一种特殊类型的声明,它能够附加到类声明,方法,属性或参数,可以修改类的行为。
通俗的讲装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、书香、方法、参数的功能。

常见的装饰器有:类装饰器、属性装饰器、方法装饰器、参数装饰器

装饰器的写法:普通装饰器(无法传参)、装饰器工厂(可传参)

装饰器是过去几年中js最大的成就之一,已是ES7的标准特性之一

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

//1.1类装饰器: 普通装饰器(无法传参)
//装饰器
function logClass(params:any){
	console.log(params)
	//params 就是当前类
	params.prototype.apiUrl='动态扩展属性'
}

@logClass
class HttpClient{
	contructor(){
	
	}
	getData(){
	
	}
}

let http:any=new HttpClient();
console.log(http.apiUrl);


//1.2 类装饰器:装饰器工厂(可传参)
function logClass(params:string){
	return function(target:any){
		console.log(target);
		console.log(params);
		target.prototype.apiUrl=params
	}
}

@logClass('http:baidu.com')
class HttpClient{
	contructor(){}
	getData(){}
}

let http=new HttpClient();
console.log(http.apiUrl);


/*
1.类装饰器
	下面是一个重载构造函数的例子
	类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
	如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。
*/
function logClass(target:any){
	console.log(target);
	return class extends target{
		apiUrl:any='我是修改后的数据'getData(){
			this.apiUrl=this.apiUrl+'---';
			console.log(this.apiUrl);
		}
	}
}

@logClass
class HttpClient{
	public apiUrl:string|undefined;
	constructor(){
		this.apiUrl='我是构造函数里面的apiUrl';
	}
	
	getData(){
		console.log(this.apiUrl);
	}
}
let http=new HttpClient();
http.getData();


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

//类装饰器
function logClass(params:string){
	return function(target:any){
		console.log(target)
		console.log(params)
	}
}
//属性装饰器
function logProperty(params:any){
	return function(target:any,attr:any){
		console.log(target);
		console.log(attr);
	}
}
@logClass('xxxx')
class HttpClient{
	@logProperty('http:baiducom')
	public url:any|undefined;
	constructor(){
		
	}
	getData(){
		
	}
}
/*
3.方法装饰器
	它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。
	方法装饰会在运行时传入下列3个参数:
		1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
		2.成员的名字
		3.成员的属性描述符
*/
// 方法装饰器一
function logMethod(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: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);
		//修改装饰器的方法 把装饰器方法里面传入的所有参数改为string类型
		//1.保存当前的方法
		let oMethod=desc.value;
		desc.value=function(...args:any[]){
			args=args.map((value)=>{
				return String(value)
			})
			console.log(args);
		}
		
	}
}
class HttpClient{
	public url:any | undefined;
	constructor(){
	
	}
	@get('http:baidu.com')
	getData(...args:any[]){
		console.log(args)
		console.log('我是getData里的方法')
	}
}
let http:any=new HttpClient();
http.getData(123'xxx');

/*
4.方法参数装饰器
	参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:
	1.对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
	2.方法的名字
	3.参数在函数参数列表中的索引
*/
function logParams(params:any){
	return function(target:any,methodName:any,paramsIndex:any){
		console.log(target);
		console.log(methodName);
		console.log(paramsIndex);
	}
}

class HttpClient{
	public url:any|undefined;
	constructor(){
	
	}
	getData(@logParams('xxx')uuid:any){
		console.log(uuid)
	}
	
}
let http=new HttpClient();
http.getData(123456)


//装饰器执行顺序

//如果有多个同样的装饰器,它会先执行后面的
function logClass1(params:string){
	return function(target:any){
		console.log('类装饰器1')
	}
}
function logClass2(params:string){
	return function(target:any){
		console.log('类装饰器2')
	}
}

function logAttribute(params?:string){
	return function(target:any){
		console.log('属性装饰器')
	}
}

function logMethod(params?:string){
	return function(target:any,attrName:any,desc:any){
		console.log('方法装饰器')
	}
}
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:baidu.com')
@logClass2('xxx')
class HttpClient{
	@logAttribute()
	public apiUrl:string | undefined;
	constructor(){}
	@logMethod()
	getData(){
		return true
	}
	setData(@logParams1() attr1:any,@logParams2() attr2:any){
			
	}
}
let http=new HttpClient();
console.log(http.apiUrl)

输出:属性装饰器 方法装饰器 方法参数装饰器2 方法参数装饰器1 类装饰器2 类装饰器1
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值