小白学Typescript

Typescript介绍

  1. Typescript是由微软开发的一款开源的编程语言
  2. Typescript是Javascript的超集,遵循最新的ES6,ES5规范。Typescript扩展了Javascript的语法。

Typescript安装 编译

安装:
使用npm命令的时候必须先安装node.js

npm i -g typescript
或者
cnpm i -g typescript(`cnpm安装:npm install -g cnpm --registry=https://registry.npm.taobao.org`)
或者
yarm global add typescript

查看是否安装成功:

tsc -v

运行:

tsc helloworld.ts

将ts代码,编译成es5代码,然后运行
在这里插入图片描述

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

  1. 通过tsc --init创建 tsconfig.json配置文件
    在这里插入图片描述
    在这里插入图片描述
  2. 运行ts
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  3. 再次保存的时候就会自动将ts编译成js来运行
    在这里插入图片描述

Tpescript中的数据类型

typescript中定义变量必须指定类型

布尔类型(boolean)

true 和 false

let flag:boolean = true;

数字类型(number)

let a:number = 123;

字符串类型(string)

let str:string = 'world';

数组类型(array)

let hobby:string[] = ["尤克里里", "爵士"];

let hobby:Array<string> = ["尤克里里", "爵士"];

元组类型(tuple)

注: 属于数组的一种,可以指定数组里面每个项的数据类型(可以指定多个数据类型)。

let arr:[string, number, boolean] = ["生活", 123, true];

枚举类型(enum)

常用于标识状态

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

pay_status 	0表示未支付  1表示支付  2表示交易成功
falg 		1表示true 	0表示false

enum Flag {
	success = 1,
	error = 0
}
let f:Flag = Flag.success;
console.log(f);		// 打印输出1

任意类型(any)

let flag:any=true;
flag = 123;

null 和 undefined

是其他数据类型(never)的子类型

let flag:undefined;
console.log(flag);  	打印输出undefined

注:一个元素可能是number类型、可能是undefined、可能是null
let flag2:undefined | number;
flag = 123;
console.log(flag2);  	打印输出123

void类型

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

function run() {
	console.log(1);
}
run();

typescript中:(表示没有返回任何类型)

function run():void {
	console.log(1);
}
run();

never类型

其他类型(包括null 和 undefined)的子类型,代表从来不会出现的值。
生命never的变量只能被never类型所赋值。

let a:null;
a = null;	// a只能等于null

let b:undefined;
b = undefined;	// b只能等于undefined

Typescript中的函数

函数声明:

  1. es5中定义函数的方法

    function run() {
    	return 'run1'
    }
    
    // 匿名函数
    var run2 = function() {
    	return 'run2'
    }
    
  2. typescript中定义函数的方法
    与es5中函数的定义最大的不同就是、typescript中函数的声明要指定数据类型

    function run():string {
    	return 'run1'
    }
    
    // 匿名函数
    var run2 = function():string {
    	return 'run2'
    }
    
  3. typescript中定义方法传参

    function getInfo(name: string, age: number):string {
    	return `${name}今年${age}岁了`;
    }
    
    // 匿名函数
    var getInfo = function(name: string, age: number):string {
    	return `${name}今年${age}岁了`;
    }
    
    // 没有返回值的函数
    function run():void {
    	console.log('123');
    }
    
  4. 方法可选参数
    es5里面的方法实参和形参可以不一样,但是在ts中形参和实参必须一样,如果不一样就需要配置可选参数。

    传递的参数后面加上了?,就代表这个参数可传可不传,注意可选参数一定要配置在参数的最后面,下面的传参name和age不能调换位置,如 function getInfo(age?: number,name: string):string,这样是不对的。

    function getInfo(name: string, age?: number):string {
    	if (age) {
    		return `${name}今年${age}岁了`;
    	}  else {
    		return `${name}今年`;
    	}
    }
    
  5. 默认参数
    es5中没法儿谁默认参数,es6中可设置默认参数

    function getInfo(name: string, age: number = 20):string {
    	if (age) {
    		return `${name}今年${age}岁了`;
    	}  else {
    		return `${name}今年`;
    	}
    }
    
  6. 剩余参数

    function sum(a: number , b: number , c: number):string {
    	return a + b + c;
    }
    
    function sum(...result:number[]):string {
    	let sum = 0;
    	for(let i = 0; i < result.length; i++) {
    		sum += result[i];
    	}
    	return sum;
    }
    alert(sum(1, 2, 3))
    
  7. 函数的重(chong)载
    java中方法的重载:重载指的是两个或者连个以上的同名函数,但是他们的参数不一样,这时会出现函数的重载的情况。
    typescript中的重载:通过为同一个函数提供多个函数类型定义来试下多种功能的目的。

    function sun(config) {
    }
    
    function sun(config, value) {
    }
    // 在es5中出现同名方法,下面的会替换掉上面的方法
    
    // 同样是函数传递不一样的参数,实现不一样的功能
    function sun(name: string):string;
    function sun(sex: boolean):boolean;
    function sun(str: any):any{
    	if (typeOf str === 'string') {
    		return name;
    	} else {
    		return str;
    	}
    }
    
    alert(sun('张三'));
    
  8. 箭头函数, es6

    setTimeout(function() {
    	alert('run');
    }, 1000)
    
    // 箭头函数中的this指向上下文
    setTimeout(() => {
    	alert('run');
    }, 1000)
    

typescript中的类

es5里面的继承

  1. es5中的类

    function Person() {
    	this.name = '张三';
    	this.age = 28;
    }
    var person = new Person();
    alert(person.name);
    
  2. 构造函数和原型链里面增加的方法

    function Person() {
    	this.name = '张三';  // 属性
    	this.age = 28;
    	this.run = function() {
    		alert(this.name);
    	}
    }
    
    // 在原型链上面扩展属性
    //  原型链上面的属性会被多个实例共享  构造函数不会
    Person.propotype.sex = "男";
    Person.propotype.work = function() {
    	alert(this.name);
    }
    
    // 通过new关键字实例化后调用的方法叫实例方法, p.work()  就是实例方法
    var person = new Person();
    p.work();
    	```
    
  3. 类里面的静态方法

    Person.getInfo = function() {
    	alert('我是静态方法');
    }
    
    // 调用静态方法
    Person.getInfo();
    
  4. es5里面的实例
    es5里面继承类 通过 原型链 + 对象冒充的组合继承方式
    原型链 + 对象冒充的组合继承方式,只能继承构造函数里面的属性和方法

    function web() {
    		Person.call(this);
    }
    var w = new web();
    w.run();	// 对象冒充可以继承构造函数里面的属性和方法
    w.work(); // 会报错,对象冒充可以继承构造函数里面的属性和方法,但是不能继承原型链的上面的属性和方法
    

    原型链实现继承
    原型链继承及可以继承构造函数里面的属性和方法,也可以继承原型链上面的方法
    缺点:实例化字类的时候没办法给父类传参

    web.prototype = new Person();  // 原型链实现继承
    var w = new web();
    w.run();
    

    原型链 + 对象冒充 的组合继承

    function Person(name, age) {
    	this.name = this.name; 
    	this.age = this.age;
    	this.run = function() {
    		alert(this.name);
    	}
    }
    

    第一种:

    function web(name, age) {
    	Person.call(this, name, age);
    }
    web.prototype = new Person();
    var w = new web("张三", 20);
    w.run();
    

    第二种:

    web.prototype = Person.propotype;
    

ts中定义类的方法

es5中定义类:

function Person(name) {
	this.name = name;
	this.run = function() {
		alert(this.name)
	}
}

var p = new Person('张三');
p.run();
class Person {
	name: string;	// 属性
	constructor(n: string) {		// 构造函数  实例化类的时候触发构造函数
		this.name = n;
	}
	
	run(): void {
		alert(this.name);
	}
}

var p = new Person('张三');
p.run();

继承

父类的方法和子类的方法一致,调用子类的方法,首先取子类的方法,如果子类没有就在父类中寻找

class Person{
	name: string;
	constructor(name: string) {
		this.name = name;
	}
	run(): void {
		return `${this.name}要睡觉了`
	}
}

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

class Child extends Person {
	constructor(name: string) {
		//  super表示调用父类的构造函数
		super(name);
	}
}
var c= new Child('张三');
alert(c.run();)

修饰符

类里面的修饰符 typescript里面定义属性的时候给我们提供了三种修饰符。
属性如果不加修饰符,默认public公有的。

  1. public : 公有的,在当前类里面、子类、类外面都可以访问
  2. private:私有的,在当前类里面可以访问
  3. protected:保护类型,在当前类、子类里面可以访问

静态属性、静态方法

es5里面的静态方法:

function Person() {
	this.run1 = function() {
	
	}
}

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

}

// 静态属性
Person.name = 'haha';

var p = new Person();

Person.run2(); // 静态方法的调用

typescript中的静态方法:

class Person {
	public name: string;
	// 静态属性
	static sex: "男";
	constructor(name: string) {
		this.name = name;
	}
	// 实例方法
	run() {
		alert(`姓名${ this.name }`);
	}
	// 静态方法
	// 注意: 静态方法只能调用静态属性
	static work() {
		alert(`${ Person.sex }孩在工作`)
	}
}

// 调用实例方法
var p = new Person('张三');
p.run();

// 调用静态方法
Person.work();
// 调用静态属性
alert(Person.sex);

多态

什么叫多态?

父类定义一个方法不去实现,让继承他的子类去实现,每个子类有不一样的表现。
多态也是继承的一种表现,多态属于继承。
class  Person {
	name: string;
	constructor(name: string) {
		this.name = name
	}
	eat() {
		console.log("今天吃什么?")
	}
} 

class Menu extends Person {
	constructor(name: string) {
		// 继承父类的属性和方法
		super();
	}
	eat() {
		return this.name + '今天吃面';
	}
}

抽象类、抽象方法

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

abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现,并且必须在派生类中实现。

abstract抽象方法只能放在抽象类里面。

抽象类和抽象方法用来定义标准。

Person 类的子类必须包含eat方法:

abstract class Person {
	public name: string;
	constructor(name: string) {
		this.name = name;
	}
	// 他的子类必须要有eat方法
	abstract eat(): any;
}
~~var p = new Person();~~   // 错误写法,抽象类不能直接被实例化

class Menu extends Person {
	// 抽象类的子类必须实现抽象类里面的抽象方法
	constructor(name: any) {
		super();
	}
	eat() {
		console.log(`${this.name}`)
	}
}

// 调用抽象方法
var  m = new Menu('小男孩');
m.eat();

typescript中的接口

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

属性接口

对json的约束:

// ts 中定义方法,
// 1. 传入参数,并且指定传递参数的数据类型
function printlabel(label: string):void {
	console.log('printlabel');
}
printlabel('haha');

// 2. ts中自定义发给发传入参数时对json进行约束
function printlabel(labelInfo{ lable: string }):void {
	console.log('printlabel');
}
~~printlabel('haha');~~    // 错误写法
printlabel({ lable: '张三' }); // 正确写法

// 3. 对批量方法传入参数进行约束
// 接口、行为和动作的规范,对批量方法进行约束
// interface 关键字定义方法(传入对象的约束、属性约束)
interface FullName {
	firstName: string; // 注意分号结束
	secondName: string;
}
function printName(name: FullName) {
	// 必须传入对象  firstName secondName
	console.log('firstName' + name.firstName + '' + name.secondName);
}

var obj = {
	age: 20,
	firstName: '张三',
	secondName: '小张'
}
printName(obj);

可选属性接口:

interface FullName {
	firstName: string; 	// 注意分号结束
	// 定义规定接口属性名后面加上?之后,证明这个参数可传可不传
	secondName?: string;	
}

function getName(name: FullName) {
	console.log(name);
}

// 参数的顺序可以不一样
getName({
	firstName: '张',
	secondName: '三'
});

小试牛刀(通过属性接口封装ajax请求):

interface Config {
	type: string;
	url: string;
	data?: string;
	dataType: string;
}
function ajax(config: Config) {
	var xhr = new XMLHttpRequest();
	xhr.open(config.url, config.url, "true");
	xhr.send(config.data);
	xhr.oreadystatechange = function() {
		if(xhr.readyState == 4 && xhr.state == 200) {
			console.log("数据请求成功");
			if (config.dataType == 'json') {
				JSON.parse(xhr.responseText)
			} else {
				console.log(xhr.responseText);
			}
		}
	}
}
ajax({
	type: 'get',
	url: 'http://www.baidu.com',
	dataType: 'json'
})

函数类型接口(批量约束)

函数类型的接口:方法传入的参数,以及返回值进行约束。
加密的函数类型接口

interface encrypt {
	(key: string, value: string): string;
}
var md: encrypt = function(key: string, value: string): string {
	// 模拟操作
	return key + value;
}
console.log(md('name', '张三'));

可索引接口

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

// 对数组的约束
interface UerArr {
	[index: number]: string
}
var arr: UerArr = ['11', '22', '33', '44', '55'];
console.log(arr[0]);

// 对对象的约束
interface UserObj {
	[index: string]: string
}
var obj: UserObj = {name: '张三'};
console.log(obj);

类类型接口

类类型接口: 对类进行约束。

// 对类的约束  和  抽象类有点儿相似
interface typeGroup {
	name: string,
	hobby(str: string): void;
}
class uerInfo implements typeGroup {
	name: string,
	construcor(name: string) {
		this.name = name;
	}
	hobby() {
		console.log(this.name);
	}
}
var h = new typeGroup('zhang'); // 打印输出 zhang

接口扩展

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

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() {
		console.log(this.name)
	}
}
var w = new web('xiao');
w.work(); // 打印输出  xiao

typescript中的泛型

泛型的定义

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

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

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

泛型函数

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

// 同时返回string类型和number类型
// 使用any相当于放弃了类型检查
function getData(vakue: any): any {
	return value;
}

// 泛型:可以支持不特定的数据类型(要求:传入的参数和返回的参数一致)
// T表示泛型,具体什么类型是调用这个方法的时候决定的
function getData<T>(vakue: T): T {
	return value;
}
getData<number>(123);

泛型类

类里面的泛型(传入什么类型的参数,返回什么类型的参数):

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

普通泛型类
class MinClass {
	public list:number[] = [];
	add(num: number) {
		this.list.push(num);
	}
	min(): num {
		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(4);
m.add(5);
m.add(6);
alert(m.min());
泛型类超集
class MinClass<T> {
	public list: T[] = [];
	add(num: T) {
		this.list.push(num);
	}
	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 MinClass<number>();
m1.add(3);
m1.add(4);
m1.add(5);
m1.add(6);
alert(m.min());
把类作为参数类型的泛型类

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

class User {
	username: string | undefined;
	password: string | undefined;
}

class MySqlDb {
	add(user: User): boolean {
		console.log(user);
		return true;
	}
}

var u = new User();
u.username = "张";
u.password = 123;
var d = new MySqlDb();
d.add(u);

--------------------------------分割--------------------------------
// 操作数据库的泛型
class MySqlDb<T> {
	add(userInfo: T): boolean {
		console.log(user);
		return true;
	}
}
// 定义一个User类,和数据库进行映射
class User {
	username: string | undefined;
	password: string | undefined;
}
var u = new User();
u.username = "张";
u.password = 123;
var d = new MySqlDb<User>();
d.add(u);

泛型接口

// 函数类型的接口
interface ConfigFun {
	(value1: string, value2: string): string;
}
var setData: ConfigFun = function(value: string,value2: string): string {
	return value1 + value2;
}
setData('n', '3');

// 泛型接口
// 1. 第一种定义泛型接口的方法
interface ConfigFun {
	<T>(value: T): T;
}
var setData: ConfigFun = function(value: T,value2: T): T{
	return value1 + value2;
}
setData<string>('n', '3');

// 2. 第二种定义泛型接口的方法
interface ConfigFun<T> {
	(value: T): T;
}
function setData<T>(value: T): T{
	return value1;
}
var mySetData: ConfigFun<string> = setData;
mySetData('N3');
typescript类型、接口、泛型综合使用–typescript封装统一操作Mysql Mongodb Mssql的底层库

功能: 定义一个操作数据库的库 只是Mysql Mssql Mongodb

要求: Mysql MsSql MongoDb功能一样 都有 add update delete get 方法

注意: 约束统一的规范,以及代码重用

解决方案: 需要约束规范,所以要定义接口,需要代码重用所以用到泛型
1. 接口:在面向对象的编程中,接口是一种规范的定义,它定义类行为和动作的规范。
2. 泛型 通俗理解:泛型就是解决类 接口 方法的复用性。

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> {
	add(info: T): boolean {
		console.log(info);
		return true;
	}
	update(info: T, id: number): boolean {
		throw new Error('Method not implementes.')
	}
	delete(id: number): boolean {
		throw new Error('Method not implementes.')
	}
	get(id: number): boolean {
		throw new Error('Method not implementes.')
	}
}
// 定义一个mssql数据库的类
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 implementes.')
	}
	delete(id: number): boolean {
		throw new Error('Method not implementes.')
	}
	get(id: number): boolean {
		throw new Error('Method not implementes.')
	}
}
// 操作用户表  定义一个user类和数据表做映射
class User {
	username: string | undefined;
	password: string | undefined;
}
u.username = "张";
u.password = 123;

// 将类作为参数来约束数据传入的类型
var mysql = new MysqlDb<User>();
mysql.add(u);
typescript中的模块

模块:TypeScript 模块的设计理念是可以更换的组织代码。模块是在其自身的作用域里执行,并不是在全局作用域,这意味着定义在模块里面的变量、函数和类等在模块外部是不可见的,除非明确地使用 export 导出它们。类似地,我们必须通过 import 导入其他模块导出的变量、函数、类等。两个模块之间的关系是通过在文件级别上使用 import 和 export 建立的。模块使用模块加载器去导入其它的模块。 在运行时,模块加载器的作用是在执行此模块代码前去查找并执行这个模块的所有依赖。 大家最熟知的JavaScript模块加载器是服务于 Node.js 的 CommonJS 和服务于 Web 应用的 Require.js。

概念:把公共的组件功能单独抽离成一个文件作为一个模块。模块里面的变量、函数、类等默认是私有的,如果我们要在外部访问模块里面的数据(变量、函数、类等),我们需要通过export暴露模块里面的数据(变量、函数、类等)。暴露后通过import引入模块就可以使用模块里面暴露的数据(变量、函数、类等)。

默认暴露export default getData,注意默认暴露在一个模块中只能使用一次。引入import getData form './modules/db';

typescript命名空间 命名空间模块化

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

// 把命名空间当作一个模块使用的时候要暴露命名空间
// export namespace A {}
// 在外面使用的时候 import {A} form './modules/a';
// var d = new A.Dog();
// d.eat();
namespace A {
	// 明明空间中的方法默认是私有的,要在外面使用命名空间里面的方法,要将命名空间里面的方法export暴露一下
	export class Dog implements Animal {
		eat() {
			console.log(111);
		}
	}
}
var d = new A.Dog();
d.eat();

namespace B {

}

typescript中的装饰器

装饰器:装饰器是一种特殊类型的声明,他能够被附加到类什么声明、方法、属性或参数上、可以修改类的行为。

通俗的讲,装饰器就是一个方法,可以注入到类、方法、属性参数上来扩展类、属性、方法、参数的功能。

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

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

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

类装饰器

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

普通装饰器:

// 装饰器
function logClass(params: any) {
	// params就是当前类
	console.log(params);
	params.prototype.apiUrl = 'XXX';
}

// 调用装饰器(无参装饰器,注意装饰器调用的后面不要加分号)
@logClass
class HttpClient {
	constructor() {

	}
	getData() {

	}
}

// 查看当前类的实例
var http:any = new HttpClient();
console.log(http.api); // 打印出动态扩展的属性  XXX

装饰器工厂:

function logClass(params: string) {
	return function(target: any) {
		console.log(target);
		console.log(params);
		params.prototype.apiUrl = 'XXX';
	}
}
// 调用装饰器
// 这里表示把 xiaochen 赋值给了 params,把 HttpClient类 赋值给了 target
@logClass('xiaochen')
class HttpClient {
	constructor() {

	}
	getData() {

	}
}
// 查看当前类的实例
var http:any = new HttpClient();
console.log(http.api); // 打印出动态扩展的属性  XXX

类装饰器重载构造函数:
类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。
如果类装饰器返回一个值,他会使用提供的构造函数类替换类的声明。

function logClass(target: any) {
	console.log(target);
	return class extends target {
		apiUrl:any = '我是修改后的数据';
	}
	getData() {
		console.log(this.apiUrl);
	}
}
@logClass
class HttpClient {
	public apiUrl: string | undefined;
	constructor() {
		this.apiUrl = '我是构造函数里面的apiUrl';
	}
	getData() {
		console.log(this.apiUrl);
	}
}
// 查看当前类的实例
var http:any = new HttpClient();
console.log(http.api); // 打印出我是修改后的数据
属性装饰器

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

// 类装饰器
function logClass(params: string) {
	return function(target: any) {
		console.log(target);
		console.log(params);
	}
}

// 属性装饰器
function logProperty(params: string) {
	// target 类的原型对象
	return function(target: any, attr: any) {
		console.log(target);
		console.log(attr);
		// 属性装饰器里面的target就相当于类装饰器里面的target.prototype
		// 就是类的原型对象,就可以修改类原型对象上面的属性
		target[attr]= params;
	}
}

// 调用装饰器
@logClass('XXX')
class HttpClient {
	// 注意:装饰器的后面不需要加上分号
	@logProperty('HHHHHHH')
	public apiUrl: string | undefined;
	constructor() {

	}
	getData() {
		console.log(apiUrl);
	}
}
// 查看当前类的实例
var http:any = new HttpClient();
http.getData();	// 打印输出 HHHHHHH 
方法装饰器

它会被应用到方法的 属性描述上,可以用来监视,修改或者替换方法的定义。
方法装饰会在运行时传入下列3个参数:
1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
2. 成员的名字
3. 成员的属性描述符

// 装饰器
function logMethod(params: any) {
	return function(target: any, methodName: any, desc: any) {
		console.log(target); // 原型对象
		console.log(methodName);	//成员名称 getData 
		console.log(desc);	//描述符
		// 修改装饰器的方法
		console.log(desc.value); //getData() {console.log(apiUrl);}
		// 修改装饰器的方法  把装饰器方法里面传入的所有参数改为string类型
		// 保存当前的方法
		var oMethod = desc.value;
		desc.value = function(...args: any[]) {
			args = arga.map((value) => {
				return String(value);
			})
			// 打印出所有的参数
			console.log(args);
			oMethod.apply(this, args); // 可以同时打印出getData方法里面的输出值,并且打印出传入的数据值
		}
	}
}
class HttpClient {
	// 注意:装饰器的后面不需要加上分号
	@logMethod('哈哈哈所发生的开发商的开发技术对接方式')
	public apiUrl: string | undefined;
	constructor() {

	}
	getData(...args: any[]) {
		console.log(args);
		console.log('我是getData里面的方法');
	}
}
// 查看当前类的实例
var http:any = new HttpClient();
http.getData(123, 'XXX')
方法参数装饰器

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

  1. 对于静成员来说是类的构造函数,对于实例成员是类的原型对象
  2. 方法的名字
  3. 参数在函数参数列表中的索引
function logMethod(params: any) {
	return function(target: any, paramsName: any, paramsIndex: any) {
		console.log(params); 	// 打印输出 uid
		console.log(target); // 原型对象 
		console.log(paramsName);	//方法名 ---  getData
		console.log(paramsIndex);	//索引 ---  12333
		target.apiUrl = params;
}
class HttpClient {
	public apiUrl: string | undefined;
	constructor() {

	}
	getData(@logMethod('uid') uid: any) {
		console.log(args);
		console.log('我是getData里面的方法');
	}
}
// 查看当前类的实例
var http:any = new HttpClient();
http.getData(12333);
// 打印出apiUrl
console.log(http.apiUrl);  // 打印输出 uid
装饰器执行的顺序
  1. 属性装饰器
  2. 方法装饰器
  3. 方法参数装饰器(有多个同样的装饰器时,执行顺序是从后向前)
  4. 类装饰器
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值