一、环境配置
1、安装
# npm 安装
npm install -g typescript
# 淘宝安装
# npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install -g typescript
# yarn安装
# npm install -g yarn
# cnpm install -g yarn
yarn global add typescript
2、验证安装
tsc -v
3、配置自动编译
-
创建tsconfig.json文件
tsc --init
-
修改配置文件
{ "compilerOptions": { ... "outDir": "./js", ... } }
-
VSCODE编辑器 -- 终端 -- 运行任务 -- tsc:监视-tsconfig.json(VSCODE新版本)
-
VSCODE编辑器 -- 任务 -- 运行任务 -- tsc:监视-tsconfig.json(VSCODE老版本)
二、数据类型
1、布尔类型(boolean)
var flag:boolean = true;
flag = false;
2、数字类型(number)
var a:number = 123;
a = 12.3;
3、字符串类型(string)
var str:string = 'this is ts'
str = '你好 ts'
4、数组类型(array)
/* 第一种定义数据的方式 */
let arrNumber:number[] = [1,2,3,4]; // 数字数组,只能放数字类型
let arrString:string[]=["java","javascript"]; // 字符串数组,只能放字符串
/* 第二种定义数据的方式 */
let arrNumber:Array<number> = [11,22,33]; // 泛型定义数字数组
let arrString:Array<string> = ["java","javascript"]; // 泛型定义字符串数组
/* 第三种定义数据的方式 */
let arrAny:any[] = [123,'123',true];
5、元组类型(tuple)
// 元组类型(tuple) 属于数组的一种
// 可以在数组中,指定多个数据类型,但是类型要一一对应
let arr:[string,number,boolean] = ["ts",13.18,true];
// let arr:[string,number,boolean] = ["ts",13.18,true,111]; 错误写法
// 不能将类型“[string, number, true, number]”分配给类型“[string, number, boolean]”
// 源具有 4 个元素,但目标仅允许 3 个。
6、枚举类型(enum)
/*
enum 枚举名 {
标识符[=整型常数],
标识符[=整型常数],
...
标识符[=整型常数],
};
*/
// 1、元素赋值,输出被赋予的值
enum Flag {
success=1,
error=-1
}
var f:Flag = Flag.success; // 打印f,输出1
// 2、元素不赋值,输出元素索引值,从0开始
enum Color {red,blue,orange};
var c:Color = Color.blue; // 打印c,输出1.
// 3、元素既有赋值,又有未赋值
// 3-1、blue赋值为数字,则orange+1
enum Color {red,blue=5,orange};
Color.blue; // 输出5
Color.orange; // 输出6
// 3-2、blue赋值为字符串,则orange也要为字符串,否则报错
enum Color {red,blue="a",orange="b"};
Color.blue; // 输出 a
Color.orange; // 输出 b
7、任意类型(any)
var num:any = 123;
num = "123"; // 不报错
num = true; // 不报错
8、null和undefined
其他(never类型)数据类型的子类型
var num1:number;
console.log(num1); // 报错
var num2:undefined;
console.log(num2); // 虽然未定值,但是可以运行
var num3:number | undefined;
num3 = 123;
console.log(num3); // 123
var num4:number | undefined;
console.log(num4); // undefined
var num5:null;
num5 = 123; // 报错
num5 = null; // 无报错
var num6:number | undefined | null;
num6 = 123;
console.log(num6); // 123
9、void
/* typescript中的void表示:
* 没有任何类型,一般用于定义方法的时候方法没有返回值
*/
// 表示函数没有任何返回类型
function run():void {
console.log('run')
}
10、never
/*
never类型:
是其他类型(包括:null和undefined)的子类型,代表从不会出现的值。
意味着声明never的变量只能被never类型所赋值
*/
var a:undefined;
a=undefined;
var b:null;
b=null;
var c:never;
// c = 123; // 错误写法
a = (()=>{
throw new Error('错误');
})()
三、函数
1、函数的定义
/* 函数声明法 */
function run():string {
return 'run';
}
/* 匿名函数 */
var fun2 = function():number{
return 123;
}
/* 定义方法传参 */
function getInfo(name:string, age:number):string {
return `${name} --- ${age}`;
}
var getInfo2 = function(name:string, age:number):string{
return `${name} --- ${age}`;
}
/* 没有返回值 */
function run:void{
console.log('run');
}
2、方法可选参数
// es5中方法的实参和形参可以不一样
// ts中必须一样,如果不一样就需要配置可选参数
function getInfo(name:string, age?:number):string {
if(age) {
return `${name} --- ${age}`;
} else {
return return `${name} --- 年龄保密`;
}
}
console.log(getInfo('张三',20)) // 张三 --- 20
console.log(getInfo('张三')) // 张三 --- 年龄保密
/* 可选参数必须配置到参数的最后边 */
3、默认参数
// es5里无法设置默认参数
// es6和ts中都可以设置默认参数
function getInfo(name:string, age:number=20):string {
return `${name} --- ${age}`;
}
console.log(getInfo('张三',30)) // 张三 --- 30
console.log(getInfo('张三')) // 张三 --- 20
4、剩余参数
// 以下方法只能接收4个参数,调用时超出,则报错
function sum(a:number,b:number,c:number,d:number):number {
return a+b+c+d;
}
sum(1,2,3,4)
// 三点运算符 接收新参传过来的值
function sum(...result:number[]):number {
var sum = 0;
for(var i=0;i<result.length;i += 1){
sum += result[i]
}
return sum;
}
sum(1,2,3,4,5,6)
// 改写1
function sum(a:number,...result:number[]):number {
var sum = a;
for(var i=0;i<result.length;i += 1){
sum += result[i]
}
return sum;
}
sum(1,2,3,4,5,6)
5、函数重载
// java中的重载:重载指的是两个或两个以上同名函数,但它们的参数不一样,这时会出现函数重载的情况。
// typescript中的重载:通过为同一个函数提供多个函数类型定义来实现多种功能的目的。
// ts为了兼容es5和es6重载的写法和java中有区别
// es5中出现同名方法,下面的会替换上面的方法
function css(config){}
function css(config,value):any{}
// ts重载
function getInfo(name:string);string;
function getInfo(age:number):number;
function getInfo(str:any):any{
if(typeof str === 'string'){
return `我叫${str}`;
} else {
return str + 1;
}
}
6、箭头函数
setTimeout(function(){alert('run')},1000)
// 箭头函数中的this指向上下文
setTimeout(()=>{alert('run')},1000)
四、类
1、es5中的类
/*
一、最简单的类
*/
function Person(){
this.name = '张三';
this.age = 20;
}
var p = new Person();
console.log(p.name); // 张三
/*********************************************************/
/*
二、构造函数和原型链里面增加方法
*/
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();
// run是实例方法,需要new Person()
p.run(); // 张三在运动
p.work(); // 张三在工作
/*********************************************************/
/*
三、类中的静态方法
*/
Person.getInfo = function() {
console.log('我是静态方法');
}
// getInfo是静态方法,无需new,直接调用即可
Person.getInfo(); // 我是静态方法
/*********************************************************/
/*
四、es5中的继承
*/
// 定义person类
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(); // 报错。对象冒充无法继承原型链上的属性和方法
# 原型链实现继承
// web类 继承Person类
function Web(){}
Web.prototype = new Person(); // 原型链实现继承
var w = new Web();
w.work(); // 张三在工作
# 原型链确实可以继承Person的构造属性和方法,还有原型链上的属性和方法,但是存在问题。
// 重新定义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(){}
Web.prototype = new Person();
# 实例化子类的时候没法给父类传参
var w = new Web('赵四',30);
w.run(); // undefined在运动
# 原型链 + 构造函数的组合继承模式(总结方式一)
// 定义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('赵四',30);
w.run(); // 赵四在运动
w.work(); // 赵四在工作
# 原型链 + 构造函数的组合继承模式(总结方式二)
// 定义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 = Person.prototype;
var w = new Web('赵四',30);
w.run(); // 赵四在运动
w.work(); // 赵四在工作
2、typescript中的类
# ts中定义类 1 #
class Person {
name: string; // 前面省略了public关键字
constructor(n:string){ // 构造函数,实例化类的时候触发的方法
this.name = n;
}
run():void{
console.log(this.name)
}
}
var p = new Person('张三');
p.run(); // 张三
# ts中定义类 2 #
class Person {
name: string; // 前面省略了public关键字
constructor(n:string){ // 构造函数,实例化类的时候触发的方法
this.name = n;
}
getName():string {
return this.name;
}
setName(name):void {
this.name = name;
}
}
var p = new Person('张三');
console.log(p.getName()) // 张三
p.setName('李四');
console.log(p.getName()) // 李四
3、typescript实现继承
// extends super
class Person {
name;string;
constructor(name:string) {
this.name = name;
}
run():string{
return `${this.name}在运动`;
}
}
class Web extends Person {
constructor(name:string){
super(name);
}
work(){
console.log(`${this.name}在工作`)
}
}
var w = new Web('李四');
console.log(w.run()); // 李四在运动
w.work(); // 李四在工作
class Web extends Person {
constructor(name:string){
super(name);
}
run():string{
return `${this.name}在运动--子类`;
}
work(){
console.log(`${this.name}在工作`)
}
}
// 字类与父类有同名方法,执行字类自己的方法
console.log(w.run()); // 李四在运动--子类
4、typescript类中的修饰符
修饰符 | 类中是否可访问 | 子类是否可访问 | 类外是否可访问 |
---|---|---|---|
public | 是 | 是 | 是 |
protected | 是 | 是 | 否 |
private | 是 | 否 | 否 |
5、typescript的静态属性和静态方法
class Person {
public name: string;
static gender:string = "男"; // 静态属性
constructor(name:string){
this.name = name;
}
run():string {
return `${this.name}在运动`;
}
static print() { // 静态方法
console.log('print')
}
}
Person.print(); // print
console.log(Person.gender); //
6、typescript的多态
// 多态:父类定义一个方法不去实现,让继承它的子类去实现,每一个子类有不同的表现
// 多态属于继承
// 动物类
class Animal {
name:string;
constructor(name:string){
this.name = name;
}
eat(){
console.log('eat')
}
}
// 狗
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、typescript的抽象方法
// 用abstract关键字定义抽象类和抽象方法,抽象类中的抽象方法不包含具体实现并且必须在派生类中实现
// abstract 抽象方法只能放在抽象类中
// 抽象类和抽象方法用来定义标准
abstract class Animal{
name:string;
constructor(name:string){
this.name = name;
}
abstract eat():any;
}
class Dog extends Animal {
constructor(name:string){
super(name);
}
// 抽象类的子类必须实现抽象类里面的抽象方法
eat(){
console.log(this.name + '吃肉')
}
}
五、接口
1、属性接口
// 对json的约束
/* 对传入对象的约束 属性接口 */
interface Fullname {
firstName:string; // 分号结束
secondName:string;
}
function printName(name: Fullname){
// 必须传入对象 firstName secondName
console.log(name.firstName + '---' + name.secondName)
}
/* 对批量方法进行约束 */
printName({
firstName:'张',
secondName:'三',
age:30
}) // 报错
printName({
firstName:'张',
secondName:'三'
}) // 正常
var obj = {
firstName:'张',
secondName:'三',
age:30
}
printName(obj) // 正常
1-1、可选属性
interface Fullname {
firstName:string; // 分号结束
secondName?:string;
}
function printName(name: Fullname){
// 必须传入对象 firstName secondName
console.log(name.firstName + '---' + name.secondName)
}
printName({
firstName:'张'
}) // 正常。无需再传secondName。因为secondName可选
1-2、案例
/* 原生js封装ajax,不兼容IE6 */
// ajax请求数据接口
interface Config {
type: string;
url:string;
data?:string;
dataType:string;
}
function ajax(config: Config) {
var xht = 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('成功');
if(config.dataType == 'json'){
console.log(JSON.parse(xhr.responseText))
}else {
console.log(xhr.resposeText)
}
}
}
}
ajax({
type: 'get',
url: 'http://api',
dataType: 'json'
})
ajax({
type: 'get',
data: 'name=zhangsan'
url: 'http://api',
dataType: 'json'
})
2、函数类型接口
// 函数类型接口:对方法传入的参数以及返回值进行约束 批量约束
/* 加密的函数类型接口 */
interface encrypt{
(key:string,value:string):string;
}
var md5: encrypt = function(key:string,value:string):string{
// 模拟操作
return key+value;
}
console.log(md5('name','zhangsan'))
3、可索引接口
# 可索引接口:数组、对象的约束(不常用)
// 对数组约束
interface UserArr {
[index:number]:string
}
var arr:UserArr = ['123','124']
// 对对象约束
interface UserObj {
[index:string]:string
}
var arr:UserObj = {name:'张三'}
4、类类型接口
# 类类型接口:对类的约束,和抽象类比较相似
interface Animal {
name:string;
eat(str:string):void;
}
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;
contructor(name:string) {
this.name = name;
}
eat(food:string){
console.log(this.name + '吃' + food)
}
}
var c = new Cat('小花');
c.eat('鱼')
5、接口扩展
# 接口扩展:接口可以继承接口
interface Animal{
eat():void;
}
interface Person extends Animal {
work():void;
}
class Web implements Person{
public name:string;
contructor(name:string){
this.name = name;
}
eat(){
console.log(this.name+'喜欢吃馒头')
}
work(){
console.log(this.name+'敲代码')
}
}
var w = new Web('小磊');
w.work();
w.eat();
# extends implements 结合使用
interface Animal{
eat():void;
}
interface Person extends Animal {
work():void;
}
class programmer {
public name:string;
contructor(name:string) {
this.name = name;
}
coding(code:string){
console.log(this.name+code)
}
}
class Web extends programmer implements Person {
contructor(name:string){
super(name)
}
eat(){
console.log(this.name+'喜欢吃馒头')
}
work(){
console.log(this.name+'敲代码')
}
}
var w = new Web('小磊');
w.coding('写ts代码')
六、泛型
1、泛型函数
// 以下只能返回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类型 (可能传入number,但是返回string。放弃了类型检查)
function getData3(value:any):any {
return value;
}
// 泛型:可以支持不特定的数据类型。要求:传入的参数和返回的参数一致
// T表示泛型,具体什么类型是调用方法的时候决定的
function getData3<T>(value:T):T {
return value;
}
getData<string>('abc')
getData<number>(123)
2、泛型类
# 泛型类:比如有个最小堆算法,需要同时支持返回数字和字符串两种类型。通过类的泛型来实现。
// 只支持number的MinClass
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+=1){
if(minNum > this.list[i]){
minNum = this.list[i];
}
}
return minNum;
}
}
var m = new MinClass();
m.add(2);
m.add(3);
m.add(4);
console.log(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+=1){
if(minNum > this.list[i]){
minNum = this.list[i];
}
}
return minNum;
}
}
3、泛型接口
// 函数类型接口
interface Configfn {
(value1:string,value2:string):string
}
var setData:Configfn = function(value1:string,value2:string):string{
return value1 + value2;
}
// 泛型改造1
interface Configfn {
<T>(value1:T):T
}
var getData:Configfn = function<T>(value:T):T{
return value;
}
getData<string>('张三')
// 泛型改造2
interface Configfn {
<T>(value1:T):T
}
function getData<T>(value:T):T{
return value;
}
var myGetData:Configfn<string>=getData;
myGetData('20')
4、泛型类拓展
// 把类作为参数来约束数据传入的类型
class User {
username: string | undefined; // 为保证username不被赋值时不报错,需要加入undefined类型
password: string | undefined;
}
class MysqlDb {
add(user:User):boolean {
return true;
}
}
var u = new User();
u.username = '张三';
u.password = '123456';
var Db = new MysqlDb();
Db.add(u);
// 泛型改造
class Article<T> {
title: string | undefined;
describe: string | undefined;
status: number | undefined;
}
class MysqlDb {
add(info:T):boolean {
return true;
}
}
var a = new Article();
a.title = '标题';
a.describe = '描述';
a.status = 1;
var Db = new MysqlDb<Article>();
Db.add(a);
七、综合使用
1、封装统一操作(Mysql|Mongodb|Mssql)
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 {
throw new Error("Method not implemented.");
}
update(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.");
}
}
class MsSqlDb<T> implements DBI<T> {
add(info: T): boolean {
throw new Error("Method not implemented.");
}
update(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.");
}
}
class User {
username: string | undefined;
password: string | undefined;
}
var u = new User();
u.username = '张三';
u.password = '123456';
var omysql = new MysqlDb<User>();
omysql.add(u);
八、模块
// ./modules/db.ts
var dbUrl = 'xxx';
export function getData():any[] {
console.log('获取数据库数据');
return [
{title:'123'},
{title:'124'}
]
}
export function save():void {
console.log('保存成功')
}
// 引入
import { getData,save } from './modules/db'
getData();
save();
// 另外一种暴露数据的方法
// ./modules/db.ts
var dbUrl = 'xxx';
function getData():any[] {
console.log('获取数据库数据');
return [
{title:'123'},
{title:'124'}
]
}
function save():void {
console.log('保存成功')
}
export {dbUrl,getData,save}
// 引入
import { getData as get,save } from './modules/db'
get();
save();
// export default:只能用一次
// ./modules/db.ts
var dbUrl = 'xxx';
function getData():any[] {
console.log('获取数据库数据');
return [
{title:'123'},
{title:'124'}
]
}
function save():void {
console.log('保存成功')
}
export default getData;
// 引入
import getData from './modules/db'
getData();
九、命名空间
// 命名空间:内部模块,主要用于组织代码,避免命名冲突
// 模块:ts的外部模块的简称,侧重代码的复用,一个模块里可能会有多个命名空间
namespace A {
interface Animal {
name: string | undefined;
eat(): void;
}
export class Dog implements Animal {
name: string | undefined;
constructor(theName:string){
this.name = theName;
}
eat(): void {
console.log(`${this.name}吃狗粮`);
}
}
export class Cat implements Animal {
name: string | undefined;
constructor(theName:string){
this.name = theName;
}
eat(): void {
console.log(`${this.name}吃猫粮`);
}
}
}
namespace B {
interface Animal {
name: string | undefined;
eat(): void;
}
export class Dog implements Animal {
name: string | undefined;
constructor(theName:string){
this.name = theName;
}
eat(): void {
console.log(`${this.name}吃狗粮`);
}
}
export class Cat implements Animal {
name: string | undefined;
constructor(theName:string){
this.name = theName;
}
eat(): void {
console.log(`${this.name}吃猫粮`);
}
}
}
var d = new A.Dog('狗'); // 命名空间A的Dog类
d.eat();
var c = new B.Cat('猫'); // 命名空间B的Cat类
c.eat();
9-1、模块化
export namespace A {
interface Animal {
name: string | undefined;
eat(): void;
}
export class Dog implements Animal {
name: string | undefined;
constructor(theName:string){
this.name = theName;
}
eat(): void {
console.log(`${this.name}吃狗粮`);
}
}
export class Cat implements Animal {
name: string | undefined;
constructor(theName:string){
this.name = theName;
}
eat(): void {
console.log(`${this.name}吃猫粮`);
}
}
}
export namespace B {
interface Animal {
name: string | undefined;
eat(): void;
}
export class Dog implements Animal {
name: string | undefined;
constructor(theName:string){
this.name = theName;
}
eat(): void {
console.log(`${this.name}吃狗粮`);
}
}
export class Cat implements Animal {
name: string | undefined;
constructor(theName:string){
this.name = theName;
}
eat(): void {
console.log(`${this.name}吃猫粮`);
}
}
}
// 引入
import {A} from './a'
var d = new A.Dog('狗');
d.eat();
十、装饰器
1、普通装饰器(不带参数)
// 装饰器
function logClass(params:any){
console.log(params); // params就是当前类
params.prototype.apiUrl = 'urlxxx';
params.prototype.run = function(){
console.log('run');
}
}
@logClass
class HttpClient {
constructor(){}
getData(){}
}
var http:any = new HttpClient();
console.log(http.apiUrl);
http.run();
2、装饰器工厂(可传参)
function logClass(params:string){
return function(target:any){
console.log(target);
console.log(params);
target.prototype.apiUrl = params;
}
}
@logClass('http://api')
class HttpClient {
constructor(){}
getData(){}
}
var http:any = new HttpClient();
console.log(http.apiUrl);
3、修改类中的构造函数和构造方法
function logClass(target:any){
console.log(target);
// 重写HttpClient函数的构造函数和构造方法
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 = new HttpClient();
http.getData();
4、属性装饰器
// 属性装饰器表达式会在运行时当作函数被调用,传入下列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);
target[attr] = params;
}
}
@logClass('http://api')
class HttpClient {
@logProperty('http://api')
public url:any | undefined;
constructor(){}
getData(){
console.log(this.url);
}
}
var http = new HttpClient();
http.getData();
5、方法装饰器
// 发放装饰器
// 应用到方法的属性描述符上,可以用来监视,修改或者替换方法定义
// 方法装饰会在运行时传入下列3个参数
// 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
// 2、成员的名字
// 3、成员的属性描述符
function get(params:any){
return function(target:any,methodName:any,describe:any){
console.log(target);
console.log(methodName);
console.log(describe);
target.apiUrl = 'xxxx';
target.run = function(){
console.log('run');
}
}
}
class HttpClient {
public url:any | undefined;
constructor(){}
@get('http://www.baidu.com')
getData(){
console.log(this.url);
}
}
var http:any = new HttpClient();
console.log(http.apiUrl);
http.run();
5-1、修改方法
function get(params:any){
return function(target:any,methodName:any,describe:any){
console.log(target);
console.log(methodName);
console.log(describe.value);
// 修改装饰器方法 把装饰器方法里面传入的所有参数改为stringl类型
// 保存当前的方法
var oMethod = describe.value;
describe.value = function(...args:any[]){
args = args.map((value)=>{
return String(value);
})
console.log(args);
}
}
}
class HttpClient {
public url:any | undefined;
constructor(){}
@get('http://www.baidu.com')
getData(){
console.log('我是getData的方法');
}
}
var http:any = new HttpClient();
http.getData(123,'xxxx');
6、方法参数装饰器
// 方法参数装饰器
// 参数装饰器表达式会在运行时当作函数被调用,可以使用参数装饰器为类的原型增加一些元素数据,传入下列3个参数:
// 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象
// 2、方法的名字
// 3、参数在函数参数列表中的索引
function logParams(params:any){
console.log(params);
return function(target:any,methodName:any,paramIndex:any){
console.log(target);
console.log(methodName);
console.log(paramIndex);
target.apiUrl = params;
}
}
class HttpClient {
public url:any | undefined;
constructor(){}
getData(@logParams('xxxxx') uuid:any){
console.log('我是getData的方法');
}
}
var http:any = new HttpClient();
http.getData(123456);
console.log(http.apiUrl);
7、装饰器的执行顺序
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,attrName:any){
console.log('属性装饰器');
}
}
function logMethod(params?:string){
return function(target:any,methodName:any,describe:any){
console.log('方法装饰器');
}
}
function logParams1(params?:string){
return function(target:any,methodName:any,paramIndex:any){
console.log('参数装饰器1');
}
}
function logParams2(params?:string){
return function(target:any,methodName:any,paramIndex:any){
console.log('参数装饰器2');
}
}
@logClass1('class1')
@logClass2('class2')
class HttpClient {
@logAttribute()
public url:any | undefined;
constructor(){}
@logMethod()
getData(){
return true;
}
setData(@logParams1() attr1:any,@logParams2() attr2:any){}
}
属性装饰器
方法装饰器
参数装饰器2
参数装饰器1
类装饰器2
类装饰器1
属性 》 方法 》 方法参数 》 类
如果有多个同样装饰器,会先执行后边的