|
装饰器(Decorators)可用来装饰类,属性,及方法,甚至是函数的参数,以改变和控制这些对象的表现,获得一些功能。
装饰器以 @expression 形式呈现在被装饰对象的前面或者上方,其中 expression 为一个函数,根据其所装饰的对象的不同,得到的入参也不同。
以下两种风格均是合法的:
ES 中装饰器处于 Stage 2 阶段 ,TypeScript 中通过开启相应编译开关来使用。
{
"compilerOptions": {
"target": "ES5",
"experimentalDecorators": true
}
}
一个简单的示例
一个简单的示例,展示了 TypeScript 中如何编写和使用装饰器。
function log(
_target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = function() {
console.log(`method ${propertyKey} called`);
return originalMethod.apply(this, arguments);
};
}
class Test {
@log
static sayHello() {
console.log("hello");
}
}
Test.sayHello();
上面的示例中,创建了名为 log 的方法,它将作为装饰器作用于类的方法上,在方法被调用时输出一条日志。作为装饰器的 log 函数其入参在后面会介绍。
执行结果:
method sayHello called
hello
装饰器的工厂方法
上面的装饰器比较呆板,设想我们想将它变得更加灵活和易于复用一些,则可以通过创建一个工厂方法来实现。因为本质上装饰器就是个普通函数,函数可通过另外的函数来创建和返回,同时装饰器的使用本质上也是一个函数调用。通过传递给工厂方法不同的参数,以获得不同表现的装饰器。
function logFactory(prefix: string) {
return function log(
_target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
const originalMethod = descriptor.value;
descriptor.value = function() {
console.log(`method ${propertyKey} called`);
return originalMethod.apply(this, arguments);
};
};
}
class Test {
@logFactory("[debug]")
static sayHello() {
console.log("hello");
}
@logFactory("[info]")
static sum() {
return 1 + 1;
}
}
Test.sayHello();
Test.sum();
执行结果:
[debug] method sayHello called
hello
[info] method sum called
多个装饰器
多个装饰器可同时作用于同一对象,按顺序书写出需要运用的装饰器即可。其求值(evaluate)和真正被执行(call)的顺序是反向的。即,排在前面的先求值,排在最后的先执行。
譬如,
function f() {
console.log("f(): evaluated");
return function(target, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("f(): called");
};
}
function g() {
console.log("g(): evaluated");
return function(target, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("g(): called");
};
}
class C {
@f()
@g()
method() {}
}
求值 的过程就体现在装饰器可能并不直接是一个可调用的函数,而是一个工厂方法或其他表达式,只有在这个工厂方法或表达式被求值后,才得到真正被调用的装饰器。
所以在这个示例中,先依次对 f() g() 求值,再从 g() 开始执行到 f()。
运行结果:
f(): evaluated
g(): evaluated
g(): called
f(): called
不同类型的装饰器
类的装饰器
作用于类(Class)上的装饰器,用于修改类的一些属性。如果装饰器有返回值,该返回值将替换掉该类的声明而作为新的构造器使用。
装饰器入参:
示例:
function sealed(constructor: Function) {
Object.seal(constructor);
Object.seal(constructor.prototype);
}
@sealed
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
greet() {
return "Hello, " + this.greeting;
}
}
@sealed 将类进行密封,将无法再向类添加属性,同时类上属性也变成不可配置的(non-configurable)。
另一个示例:
function classDecorator<T extends { new (...args: any[]): {} }>(
constructor: T
) {
return class extends constructor {
newProperty = "new property";
hello = "override";
};
}
@classDecorator
class Greeter {
property = "property";
hello: string;
constructor(m: string) {
this.hello = m;
}
}
console.log(new Greeter("world"));
因为 @classDecorator 中有返回值,这个值将替换本来类的定义,当 new 的时候,使用的是装饰器中返回的构造器来创建类。
方法的装饰器
装饰器作用于类的方法时可用于观察,修改或替换该方法。如果装饰器有返回值,将替换掉被作用方法的属性描述器(roperty Descriptor)。
装饰器入参依次为:
- 作用于静态方法时为类的构造器,实例方法时为类的原型(prototype)。
- 被作用的方法的名称。
- 被作用对象的属性描述器。
示例:
function enumerable(value: boolean) {
return function(
target: any,
propertyKey: string,
descriptor: PropertyDescriptor
) {
descriptor.enumerable = value;
};
}
class Greeter {
greeting: string;
constructor(message: string) {
this.greeting = message;
}
@enumerable(false)
greet() {
return "Hello, " + this.greeting;
}
}
上面示例中 @enumerable 改变了被装饰方法的 enumerable 属性,控制其是否可枚举。
类的方法可以是设置器(setter)或获取器(getter)。当两者成对出现时,应当只对其中一个运用装饰器,谁先出现就用在谁身上。因为装饰器应用时是用在 get 和 set 两者合并的属性描述器上的。
class Test {
private _foo = 1;
@logFactory("[info]")
get foo() {
return this._foo;
}
//
- 从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框架,想到要研究底层代码. 注:本人前端小白一枚,文章旨在记录自己 ...
- TypeScript装饰器(decorators)
装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上,可以修改类的行为. 装饰器使用 @expression这种形式,expression求值后必须为一个函数,它会在运行时被 ...
- TypeScript 装饰器的执行原理
装饰器本质上提供了对被装饰对象 Property Descriptor 的操作,在运行时被调用. 因为对于同一对象来说,可同时运用多个装饰器,然后装饰器中又可对被装饰对象进行任意的修改甚至是替换掉实 ...
- typescript装饰器 方法装饰器 方法参数装饰器 装饰器的执行顺序
/* 装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为. 通俗的讲装饰器就是一个方法,可以注入到类.方法.属性参数上来扩展类.属性.方法.参数的功能. 常 ...
- typescript装饰器定义 类装饰器 属性装饰器 装饰器工厂
/* 装饰器:装饰器是一种特殊类型的声明,它能够被附加到类声明,方法,属性或参数上,可以修改类的行为. 通俗的讲装饰器就是一个方法,可以注入到类.方法.属性参数上来扩展类.属性.方法.参数的功能. 常 ...
- TypeScript 中装饰器的理解?应用场景?
一.是什么 装饰器是一种特殊类型的声明,它能够被附加到类声明,方法, 访问符,属性或参数上 是一种在不改变原类和使用继承的情况下,动态地扩展对象功能 同样的,本质也不是什么高大上的结构,就是一个普通的 ...
- Typescript中的装饰器原理
Typescript中的装饰器原理 1.小原理 因为react中的高阶组件本质上是个高阶函数的调用, 所以高阶组件的使用,我们既可以使用函数式方法调用,也可以使用装饰器. 也就是说,装饰器的本质就是一 ...
随机推荐
- css画三角形
效果图: 代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- rails中一个窗体多个模型——fields_for
详细参考 http://railscasts.com/episodes/73-complex-forms-part-1中part-1.2.3部分 借助field_for可以生成表单来处理两个或更多模型 ...
- java基础知识(3)----面向对象
三:面向对象:特点: 1:将复杂的事情简单化.2:面向对象将以前的过程中的执行者,变成了指挥者.3:面向对象这种思想是符合现在人们思考习惯的一种思想. 过程和对象在我们的程序中是如何体现的呢?过程其实 ...
- Hibernate---Hql查询2---
hibernate.cfg.xml配置: <?xml version='1.0' encoding='UTF-8'?> <!DOCTYPE hibernate-configurati ...
- VIsual Studio 2010 常用快捷键
1.Ctrl+S 保存 2.Ctrl+F: 查找 3.Ctrl+H: 替换 4.Ctrl+E,S: 查看空白 5.Ctrl+K+C: 注释选定内容 6.Ctrl+K+U: 取消选定注释内容 7.C ...
- day02 秘钥生成,免密访问命令
hadoop免密登陆: 生成秘钥: ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa cat ~/.ssh/id_dsa.pub >> ~/.ssh/aut ...
- 机器学习前沿热点——Deep Learning
深度学习是机器学习研究中的一个新的领域,其动机在于建立.模拟人脑进行分析学习的神经网络,它模仿人脑的机制来解释数据,例如图像.声音和文本.深度学习是无监督学习的一种. 深度学习的概念源于人工神经网络的 ...
- Servlet编程实例 续1
-----------------siwuxie095 在 LoginServlet 中,右键->Open Type Hierar ...
- 8、linux-数字计算
bash内置了对整数四则运算的支持,但是并不支持浮点运算 bc命令是一种支持任意精度的交互执行的计算器语言,而bc命令可以很方便的进行浮点运算,当然整数运算也不再话下 在bc工作环境下,可以使用以下计 ...
- p2320&bzoj1192 鬼谷子的钱袋
传送门(洛谷) 传送门(bzoj) 题目 鬼谷子非常聪明,正因为这样,他非常繁忙,经常有各诸侯车的特派员前来向他咨询时政.有一天,他在咸阳游历的时候,朋友告诉他在咸阳最大的拍卖行(聚宝商行)将要举行一 ...
|