Angular 2 Decorators - 1

在我们深入了解 Angular 2 中 @NgModule、@Component、@Injectable 等常见的装饰器之前,我们要先了解 TypeScript 中的装饰器。装饰器是一个非常酷的特性,最早出现在 Google 的 AtScript 中,它出现的目的是为了让开发者,开发出更容易维护、更容易理解的 Angular 代码。令人兴奋的是,在2015年 Angular 团队跟 MicroSoft 的 TypeScript 团队经过数月的的交流,最终决定采用 TypeScript 来重写 Angular 2 项目 。

装饰器是什么

  • 它是一个表达式

  • 该表达式被执行后,返回一个函数

  • 函数的入参分别为 targe、name 和 descriptor

  • 执行该函数后,可能返回 descriptor 对象,用于配置 target 对象 

装饰器的分类

  • 类装饰器 (Class decorators)

  • 属性装饰器 (Property decorators)

  • 方法装饰器 (Method decorators)

  • 参数装饰器 (Parameter decorators)

TypeScript 类装饰器

类装饰器声明:

declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void

类装饰器顾名思义,就是用来装饰类的。它接收一个参数:

  • target: TFunction - 被装饰的类

看完第一眼后,是不是感觉都不好了。没事,我们马上来个例子:

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;

属性装饰器顾名思义,用来装饰类的属性。它接收两个参数:

  • target: Object - 被装饰的类

  • propertyKey:string | symbol - 被装饰类的属性名

趁热打铁,马上来个例子热热身:

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 {@LogChangesname: 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, key, {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;

方法装饰器顾名思义,用来装饰类的属性。它接收三个参数:

  • target: Object - 被装饰的类

  • propertyKey: string | symbol - 方法名

  • descriptor: TypePropertyDescript - 属性描述符

废话不多说,直接上例子:

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 {@LogOutputdouble (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, propertyKey: string | symbol, parameterIndex: number ) => void

参数装饰器顾名思义,是用来装饰函数参数,它接收三个参数:

  • target: Object - 被装饰的类

  • propertyKey: string | symbol - 方法名

  • parameterIndex: number - 方法中参数的索引值

function Log(target: Function, key: string, parameterIndex: number) {var functionLogged = key || target.prototype.constructor.name;console.log(`The parameter in position ${parameterIndex} at ${functionLogged} hasbeen 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) ,参数说明如下:

  • obj 需要定义的属性对象

  • prop 需被定义或修改的属性名

  • descriptor 需被定义或修改的属性的描述符

对象里目前存在的属性描述符有两种主要形式:数据描述符和存取描述符。数据描述符是一个拥有可写或不可写值的属性。存取描述符是由一对 getter-setter 函数功能来描述的属性。描述符必须是两种形式之一,不能同时是两者。

数据描述符和存取描述符均具有以下可选键值:

  • configurable
    当且仅当该属性的 configurable 为 true 时,该属性才能够被改变,也能够被删除。默认为 false。

  • enumerable
    当且仅当该属性的 enumerable 为 true 时,该属性才能够出现在对象的枚举属性中。默认为 false。

数据描述符同时具有以下可选键值:

  • value
    该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等)。默认为 undefined。

  • writable
    当且仅当仅当该属性的writable为 true 时,该属性才能被赋值运算符改变。默认为 false。

存取描述符同时具有以下可选键值:

  • get
    一个给属性提供 getter 的方法,如果没有 getter 则为 undefined。该方法返回值被用作属性值。默认为undefined。

  • set
    一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。该方法将接受唯一参数,并将该参数的新值分配给该属性。默认为undefined。

使用示例:

var o = {}; // 创建一个新对象
Object.defineProperty(o, "a", {value : 37, writable : true, enumerable : true,     configurable : true});  

总结

本文主要介绍了 TypeScript 中的四种装饰器,了解装饰器的基本分类和实现原理,为我们下一篇深入 Angular 2 的 @NgModule、@Component、@Injectable 等常用装饰器做好铺垫。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/291227.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode之Relative Ranks

1、题目 Given scores of N athletes, find their relative ranks and the people with the top three highest scores, who will be awarded medals: "Gold Medal", "Silver Medal" and "Bronze Medal". Example 1: Input: [5, 4, 3, 2, 1] Out…

php yii 插入,Yii2 批量插入、更新数据实例

在使用yii2开发项目时,有时候会遇到这样的情况:向后台发送多条数据,其中一些数据已经存在记录,只需要对其部分字段的值进行修改;而另一部分的数据则需要新添加进去.这就需要对添加的数据进行判断,其中一些执行update,剩下的执行insert代码如下,不对的地方请指教://批量更新,并将…

c++代码寻找USB00端口并添加打印机

USB00*端口的背景 插入USB端口的打印机&#xff0c;安装打印机驱动&#xff0c;在控制面板设备与打印机处的打印机对象上右击&#xff0c;可以看到打印机端口。对于不少型号&#xff0c;这个端口是USB001或USB002之类的。 经观察&#xff0c;这些USB00*端口并不是打印机驱动所…

WCF中使用控件的委托,线程中的UI委托

UI界面&#xff1a; <Window x:Class"InheritDemo.Window1"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml"Title"Window1" Height"300" Widt…

.NET6之MiniAPI(十七):缓存

缓存是空间换时间的一种做法&#xff0c;可以有效的提升响应时间&#xff0c;asp.net core引入了本地内存缓存和分布式缓存。先看一下本地内存缓存&#xff1a;using Microsoft.Extensions.Caching.Memory; using Microsoft.Extensions.Internal;var builder WebApplication.C…

Android之机端安装apk出现INSTALL_FAILED_INSUFFICIENT_STORAGE错误的解决方法

1、错误 INSTALL_FAILED_INSUFFICIENT_STORAGE 2、解决办法 是由于手机存储不足了&#xff0c;删除一些app,给手机留下足够的空间即可。

IOS调用WCF提供的服务方法,但是方法的参数是WCF那边自定义的对象,这样有办法调用么,如果可以IOS应该怎么传参呢?请问有了解的么,...

最近做一个项目后端使用WCF接收Android手机拍照并带其它参数保存到服务器里&#xff1b;刚好把最近学习的WCF利用上&#xff0c;本以为是个比较简单的功能应该很好实现&#xff0c;没想到其中碰到不少问题&#xff0c;在网上搜索很久一直没有想到的解决方案&#xff0c;最后实现…

php数据表格的重载,layui数据表格实现重载数据表格功能(搜索功能)

layui数据表格实现重载数据表格功能&#xff0c;以搜索功能为例加载数据表格实现搜索功能和数据表格重载全部代码加载数据表格按照layui官方文档示例HTML部分JavaScript部分var table layui.table;//执行渲染table.render({elem: #demo //指定原始表格元素选择器(推荐id选择器…

python读取windows系统的文件后print乱码问题的解决

我用的是2.7 先文件头用老办法 import sysreload(sys)sys.setdefaultencoding("utf-8") 后 print filename.decode(gbk).encode(utf-8)转载于:https://www.cnblogs.com/leomo/p/6528064.html

JAVA学习博客---2015.5

上一次的学习博客写的和流水账差不多&#xff0c;有点生硬的和背目录一样&#xff0c;所以既然学习的目的是程序&#xff0c;那么这个月的学习博客就用程序来说点东西吧。这个月看了一些C和JAVA的视频&#xff0c;开始看别人写的程序&#xff0c;能看的懂但是自己去写的话前后逻…

ABP vNext微服务架构详细教程——项目部署

1基础配置在之前的文章中&#xff0c;我们已经配置了Kubernetes集群并安装了管理工具Kubesphere&#xff0c;文章地址为&#xff1a;https://mp.weixin.qq.com/s/MgpdMv5A-fYxN7XY8N9Djw登录Kubesphere页面&#xff0c;打开工作台&#xff0c;在平台资源选项卡中点击“企业空间…

LeetCode之Sqrt(x)

1、题目 Implement int sqrt(int x). Compute and return the square root of x. Subscribe to see which companies asked this question. 2、代码实现 public class Solution {public int mySqrt(int x) {if (x < 0)return -1;if (x 0)return 0; if (x 1) return 1;int …

offsetTop和scrollTop的差别

近期想写个组件&#xff0c;结果被这两个属性搞的有点晕&#xff0c;查了下文档和资料&#xff0c;对这两个属性总结例如以下&#xff1a; 一直以来对offsetLeft&#xff0c;offsetTop&#xff0c;scrollLeft&#xff0c;scrollTop这几个方法非常迷糊&#xff0c;花了一天的时间…

php post授权编写,php模拟post行为代码总结(POST方式不是绝对安全)

GET行为比较简单&#xff0c;POST比较复杂一些。这里提供两种方法供选择&#xff1a;第一&#xff1a;手写代码。第二&#xff1a;利用HttpClient php类库第一种方法&#xff1a;PHP代码$flag 0;//要post的数据$argv array(var1>abc,var2>你好吗);//构造要post的字符串…

走向思考

走向思考 最近因为工作的原因&#xff0c;好几天没有更新文章了...... 今天下午面试回来(以失败告终)&#xff0c;睡了一觉&#xff0c;夜里不困&#xff0c;于是就写了写说起工作(我指的是软件行业&#xff0c;其他专业也雷同)&#xff0c;怎么说呢&#xff1f;只有亲身体会才…

quartz (一) 基于 Quartz 开发企业级任务调度应用

本文转自&#xff1a;http://www.ibm.com/developerworks/cn/opensource/os-cn-quartz/ Quartz 基本概念及原理 Quartz Scheduler 开源框架 Quartz 是 OpenSymphony 开源组织在任务调度领域的一个开源项目&#xff0c;完全基于 Java 实现。该项目于 2009 年被 Terracotta 收购&…

C# 11 中的参数 null 检查

C# 11 中的参数 null 检查IntroC# 11 将引入一个新的操作符 !! 来简化我们代码中的对于参数的 null 检查&#xff0c;昨天发布的 .NET 7 Preview 1 已经支持了这一语法&#xff0c;感兴趣的不妨来试一下吧&#xff0c;下面我们就来看一下如何使用吧Prepare如果你想在本地代码中…

java之简单的Callback使用总结

1、什么是Callback,什么时候需要使用Callback callback是回调的意思&#xff0c;一般我们需要2个类需要相互掉用&#xff0c;一个类把数据动态传递给另外一个类的时候&#xff0c;可以用这种方式&#xff0c;比如Android里面的Launcher类和LauncherModel类&#xff0c;Launcher…

2017-03-10Git版本回退

1再次修改内容&#xff1a;Git is a distributed version control system. Git is free software distributed under the GPL. 2提交&#xff1a;$ git add readme.txt$ git commit -m "append GPL" [master 3628164] append GPL 1 file changed, 1 insertion(), 1 d…

cms的 php代码,KingCMS/PHP可执行代码

实例:Example :{king:title/}{king:content/}作者:{king:_author/}上面的代码没有什么特别的地方&#xff0c;但客户的要求有了变化&#xff0c;他想在详细页的内容开始前调用缩略图&#xff0c;没有则忽略。所以问题也来了&#xff0c;因为有的文章有缩略图&#xff0c;有的没…