TypeScript装饰器(decorators)
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上,可以修改类的行为。 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。
例:
@Path('/hello')
class HelloService {}
在TypeScript中装饰器还属于实验性语法,所以要想使用必须在配置文件中tsconfig.json编译选项中开启:
{
"compilerOptions": {
"experimentalDecorators": true
}
}
如何定义装饰器
装饰器本身其实就是一个函数,理论上忽略参数的话,任何函数都可以当做装饰器使用。例:
demo.ts
function Path(target:any) {
console.log("I am decorator.")
}
@Path
class HelloService {}
使用tsc编译后,执行命令node demo.js,输出结果如下:
I am decorator.
装饰器执行时机
修饰器对类的行为的改变,是代码编译时发生的(不是TypeScript编译,而是js在执行机中编译阶段),而不是在运行时。这意味着,修饰器能在编译阶段运行代码。也就是说,修饰器本质就是编译时执行的函数。
在Node.js环境中模块一加载时就会执行
函数柯里化解决参数问题
但是实际场景中,有时希望向装饰器传入一些参数, 如下:
@Path("/hello", "world")
class HelloService {}
此时上面装饰器方法就不满足了(VSCode编译报错),这是我们可以借助JavaScript中函数柯里化特性
function Path(p1: string, p2: string) {
return function (target) { // 这才是真正装饰器
// do something
}
}
五种装饰器
在TypeScript中装饰器可以修饰四种语句:类,属性,访问器,方法以及方法参数。
1 类装饰器
应用于类构造函数,其参数是类的构造函数。
注意class并不是像Java那种强类型语言中的类,而是JavaScript构造函数的语法糖。
function Path(path: string) {
return function (target: Function) {
!target.prototype.$Meta && (target.prototype.$Meta = {})
target.prototype.$Meta.baseUrl = path;
};
}
@Path('/hello')
class HelloService {
constructor() {}
}
console.log(HelloService.prototype.$Meta);// 输出:{ baseUrl: '/hello' }
let hello = new HelloService();
console.log(hello.$Meta) // 输出:{ baseUrl: '/hello' }
2 方法装饰器
它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。
方法装饰会在运行时传入下列3个参数:
- 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 2、成员的名字。
- 3、成员的属性描述符。
function GET(url: string) {
return function (target, methodName: string, descriptor: PropertyDescriptor) {
!target.$Meta && (target.$Meta = {});
target.$Meta[methodName] = url;
}
}
class HelloService {
constructor() { }
@GET("xx")
getUser() { }
}
console.log((<any>HelloService).$Meta);
注意:在vscode编辑时有时会报作为表达式调用时,无法解析方法修饰器的签名。错误,此时需要在tsconfig.json中增加target配置项:
{
"compilerOptions": {
"target": "es6",
"experimentalDecorators": true,
}
}
3 方法参数装饰器
参数装饰器表达式会在运行时当作函数被调用,传入下列3个参数:
- 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 2、参数的名字。
- 3、参数在函数参数列表中的索引。
function PathParam(paramName: string) {
return function (target, methodName: string, paramIndex: number) {
!target.$Meta && (target.$Meta = {});
target.$Meta[paramIndex] = paramName;
}
}
class HelloService {
constructor() { }
getUser( @PathParam("userId") userId: string) { }
}
console.log((<any>HelloService).prototype.$Meta); // {'0':'userId'}
4 属性装饰器
属性装饰器表达式会在运行时当作函数被调用,传入下列2个参数:
- 1、对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
- 2、成员的名字。
function DefaultValue(value: string) {
return function (target: any, propertyName: string) {
target[propertyName] = value;
}
}
class Hello {
@DefaultValue("world") greeting: string;
}
console.log(new Hello().greeting);// 输出: world
装饰器加载顺序
function ClassDecorator() {
return function (target) {
console.log("I am class decorator");
}
}
function MethodDecorator() {
return function (target, methodName: string, descriptor: PropertyDescriptor) {
console.log("I am method decorator");
}
}
function Param1Decorator() {
return function (target, methodName: string, paramIndex: number) {
console.log("I am parameter1 decorator");
}
}
function Param2Decorator() {
return function (target, methodName: string, paramIndex: number) {
console.log("I am parameter2 decorator");
}
}
function PropertyDecorator() {
return function (target, propertyName: string) {
console.log("I am property decorator");
}
}
@ClassDecorator()
class Hello {
@PropertyDecorator()
greeting: string;
@MethodDecorator()
greet( @Param1Decorator() p1: string, @Param2Decorator() p2: string) { }
}
输出结果:
I am property decorator
I am parameter2 decorator
I am parameter1 decorator
I am method decorator
I am class decorator
从上述例子得出如下结论:
1、有多个参数装饰器时:从最后一个参数依次向前执行
2、方法和方法参数中参数装饰器先执行。
3、类装饰器总是最后执行。
4、方法和属性装饰器,谁在前面谁先执行。因为参数属于方法一部分,所以参数会一直紧紧挨着方法执行。上述例子中属性和方法调换位置,输出如下结果:
I am parameter2 decorator
I am parameter1 decorator
I am method decorator
I am property decorator
I am class decorator
TypeScript装饰器(decorators)的更多相关文章
- 从C#到TypeScript - 装饰器
总目录 从C#到TypeScript - 类型 从C#到TypeScript - 高级类型 从C#到TypeScript - 变量 从C#到TypeScript - 接口 从C#到TypeScript ...
- 基于TypeScript装饰器定义Express RESTful 服务
前言 本文主要讲解如何使用TypeScript装饰器定义Express路由.文中出现的代码经过简化不能直接运行,完整代码的请戳:https://github.com/WinfredWang/expre ...
- Angular 个人深究(一)【Angular中的Typescript 装饰器】
Angular 个人深究[Angular中的Typescript 装饰器] 最近进入一个新的前端项目,为了能够更好地了解Angular框架,想到要研究底层代码. 注:本人前端小白一枚,文章旨在记录自己 ...
- 【低门槛 手把手】python 装饰器(Decorators)原理说明
本文目的是由浅入深地介绍python装饰器原理 装饰器(Decorators)是 Python 的一个重要部分 其功能是,在不修改原函数(类)定义代码的情况下,增加新的功能 为了理解和实现装饰器,我们 ...
- TypeScript 装饰器
装饰器(Decorators)可用来装饰类,属性,及方法,甚至是函数的参数,以改变和控制这些对象的表现,获得一些功能. 装饰器以 @expression 形式呈现在被装饰对象的前面或者上方,其中 ex ...
- TypeScript 装饰器的执行原理
装饰器本质上提供了对被装饰对象 Property Descriptor 的操作,在运行时被调用. 因为对于同一对象来说,可同时运用多个装饰器,然后装饰器中又可对被装饰对象进行任意的修改甚至是替换掉实 ...
- Python装饰器(Decorators )
http://book.pythontips.com/en/latest/decorators.html 在<Built-in Functions(3.6)>和<Python上下文管 ...
- Python 装饰器(Decorators) 超详细分类实例
Python装饰器分类 Python 装饰器函数: 是指装饰器本身是函数风格的实现; 函数装饰器: 是指被装饰的目标对象是函数;(目标对象); 装饰器类 : 是指装饰器本身是类风格的实现; 类 ...
- typescript装饰器 方法装饰器 方法参数装饰器 装饰器的执行顺序
/* 装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为. 通俗的讲装饰器就是一个方法,可以注入到类.方法.属性参数上来扩展类.属性.方法.参数的功能. 常 ...
随机推荐
- ubuntu下加载mcypt
mcrypt 是php 里面重要的加密支持扩展库,linux环境下:该库在默认情况下不开启.window环境下:PHP>=5.3,默认开启mcrypt扩展 1.命令行下载(不嫌麻烦可以到网上找安 ...
- chown 命令详解
chown 作用:改变某个文件或目录的所有者和所属的组, 该命令可以向某个用户授权,使该用户编程指定文件的所有者或者改变文件的所属组, 用户可以是用户或者是用户ID, 用户组可以是组名或者租ID, ...
- 转 - .net/c# 使用RabbitMQ
背景 最近需要用C#写一个Adapter来做数据传输,合作方使用的是RabbitMQ,所以我这边也要跟着写写... 在网上搜索了一些,发现园子里的这篇写的还是非常好的.虽然有点老了,我自己用的是最新的 ...
- 本机向windows服务器传输文件的三种方法
闲来无事,在腾讯云上申请了一个免费的服务器,想将自己写的网页发布到服务器上,服务器的申请很简单,百度搜索 腾讯云 ,然后新人第一次注册能申请到免费一个月的云主机,虽然配置不怎么高,但是还是能用的,这是 ...
- Python核心编程--浅拷贝与深拷贝
一.问题引出浅拷贝 首先看下面代码的执行情况: a = [1, 2, 3] print('a = %s' % a) # a = [1, 2, 3] b = a print('b = %s' % b) ...
- 服务器 Python服务停服、起服脚本
近日,在阿里云服务器上部署了一个Python,Web框架为Tornado,服务器为Ubuntu 16.04. 服务的启动也十分的简单: python services.py 我是利用Xshell工具连 ...
- C# 调用动态链接库,给游览器写入Cookie
样例代码: class Program { /// <summary> /// 写 /// </summary> /// <param name="lpszUr ...
- 菜鸟之旅——初识.NET
入坑.Net 也已经两年多了,既然在微软.Net 体系下混,对.Net 体系也需要了解一下,当然这些知识也都是查阅资料都能够查到的,这里主要是对自己所学的整理,况且最近的学习有些闭门造车的味道,现在想 ...
- VS代码生成工具ReSharper使用手册:配置快捷键(转)
原文:http://blog.csdn.net/fhzh520/article/details/46364603 VS代码生成工具ReSharper提供了丰富的快捷键,可以极大地提高你的开发效率. 配 ...
- [js高手之路] vue系列教程 - 绑定设置属性的多种方式(5)
一.设置属性的值: {{data中的数据}} window.onload = function () { var c = new Vue({ el : '#box', data : { url : ' ...