Angular 2 Decorators - 1
在我们深入了解 Angular 2 中 @NgModule、@Component、@Injectable 等常见的装饰器之前,我们要先了解 TypeScript 中的装饰器。装饰器是一个非常酷的特性,最早出现在 Google 的 AtScript 中,它出现的目的是为了让开发者,开发出更容易维护、更容易理解的 Angular 代码。令人兴奋的是,在2015年 Angular 团队跟 MicroSoft 的 TypeScript 团队经过数月的的交流,最终决定采用 TypeScript 来重写 Angular 2 项目 。 装饰器是什么
装饰器的分类
TypeScript 类装饰器类装饰器声明: declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void 类装饰器顾名思义,就是用来装饰类的。它接收一个参数:
看完第一眼后,是不是感觉都不好了。没事,我们马上来个例子: function Greeter(target: Function): void { target.prototype.greet = function (): void { console.log('Hello!'); } } @Greeter class Greeting { constructor() { // 内部实现 } } let myGreeting = new Greeting(); myGreeting.greet(); // console output: 'Hello!'; 上面的例子中,我们定义了 Greeter 类装饰器,同时我们使用了 @Greeter 新的语法,来使用装饰器。 (备注:读者可以直接复制上面的代码,在 TypeScript Playground 中运行查看结果)。 有的读者可能想问,例子中总是输出 Hello! ,能自定义输出的问候语么 ?这个问题很好,答案是可以的。具体实现如下: function Greeter(greeting: string) { return function(target: Function) { target.prototype.greet = function(): void { console.log(greeting); } } } @Greeter('您好') class Greeting { constructor() { // 内部实现 } } let myGreeting = new Greeting(); myGreeting.greet(); // console output: '您好!'; TypeScript 属性装饰器属性装饰器声明: declare type PropertyDecorator = (target:Object,propertyKey: string | symbol ) => void; 属性装饰器顾名思义,用来装饰类的属性。它接收两个参数:
趁热打铁,马上来个例子热热身: function LogChanges(target: Object,key: string) { var propertyValue: string = this[key]; if(delete this[key]) { Object.defineProperty(target,key,{ get: function () { return propertyValue; },set: function(newValue) { propertyValue = newValue; console.log(`${key} is now ${propertyValue}`); } }); } } class Fruit { @LogChanges name: string; } let fruit = new Fruit(); fruit.name = 'apple'; // console output: 'name is now apple' fruit.name = 'banana'; // console output: 'name is now banana' 那么问题来了,如果用户想在属性变化的时候,自动刷新页面,而不是简单地在控制台输出消息,那要怎么办?我们能不能参照类装饰器自定义问候语的方式,来实现监测属性变化的功能。具体实现如下: function LogChanges(callbackObject: any) { return function(target: Object,key: string): void { var propertyValue: string = this[key]; if(delete this[key]) { Object.defineProperty(target,{ get: function () { return propertyValue; },set: function(newValue) { propertyValue = newValue; callbackObject.onchange.call(this,propertyValue); } }); } } } class Fruit { @LogChanges({ onchange: function(newValue: string): void { console.log(`The fruit is ${newValue} now`); } }) name: string; } let fruit = new Fruit(); fruit.name = 'apple'; // console output: 'The fruit is apple now' fruit.name = 'banana'; // console output: 'The fruit is banana now' TypeScript 方法装饰器方法装饰器声明: declare type MethodDecorator = <T>(target:Object,propertyKey: string | symbol,descriptor: TypePropertyDescript<T>) => TypedPropertyDescriptor<T> | void; 方法装饰器顾名思义,用来装饰类的属性。它接收三个参数:
废话不多说,直接上例子: function LogOutput(tarage: Function,key: string,descriptor: any) { var originalMethod = descriptor.value; var newMethod = function(...args: any[]): any { var result: any = originalMethod.apply(this,args); if(!this.loggedOutput) { this.loggedOutput = new Array<any>(); } this.loggedOutput.push({ method: key,parameters: args,output: result,timestamp: new Date() }); return result; }; descriptor.value = newMethod; } class Calculator { @LogOutput double (num: number): number { return num * 2; } } let calc = new Calculator(); calc.double(11); // console ouput: [{method: "double",output: 22,...}] console.log(calc.loggedOutput); 最后我们来看一下参数装饰器: TypeScript 参数装饰器参数装饰器声明: declare type ParameterDecorator = (target: Object,parameterIndex: number ) => void 参数装饰器顾名思义,是用来装饰函数参数,它接收三个参数:
function Log(target: Function,parameterIndex: number) { var functionLogged = key || target.prototype.constructor.name; console.log(`The parameter in position ${parameterIndex} at ${functionLogged} has been decorated`); } class Greeter { greeting: string; constructor(@Log phrase: string) { this.greeting = phrase; } } // console output: The parameter in position 0 at Greeter has // been decorated 我有话说1.Object.defineProperty() 方法有什么用 ? Object.defineProperty 用于在一个对象上定义一个新的属性或者修改一个已存在的属性,并返回这个对象。 方法的签名:Object.defineProperty(obj,prop,descriptor) ,参数说明如下:
对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个拥有可写或不可写值的属性。存取描述符是由一对 getter-setter 函数功能来描述的属性。描述符必须是两种形式之一,不能同时是两者。 数据描述符和存取描述符均具有以下可选键值:
数据描述符同时具有以下可选键值:
存取描述符同时具有以下可选键值:
使用示例: var o = {}; // 创建一个新对象 Object.defineProperty(o,"a",{value : 37,writable : true,enumerable : true,configurable : true}); 总结本文主要介绍了 TypeScript 中的四种装饰器,了解装饰器的基本分类和实现原理,为我们下一篇深入 Angular 2 的 @NgModule、@Component、@Injectable 等常用装饰器做好铺垫。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |