JavaScript Decorator 的使用方法可以看这两篇文章:Legacy JavaScript Decorator 和 JavaScript Decorator
本章内容介绍 Decorator 内部的原理,typescript 是如何实现 decorator 的。
为了启用 decorator 语法,需要配置 tsconfig.json 文件:
{
"compilerOptions": {
"target": "ESNext",
"experimentalDecorators": true,
"emitDecoratorMetadata": false
},
"include": ["./**/*.ts"]
}
包含 decorator 语法的 TypeScript 文件:
function Enumerable(
target: any,
propertyKey: string | symbol,
descriptor: PropertyDescriptor,
) {
descriptor.enumerable = true;
return descriptor;
}
class Demo {
@Enumerable
public foo() {
// do nothing
}
}
const demo = new Demo();
编译后的 js 文件:
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
function Enumerable(target, propertyKey, descriptor) {
descriptor.enumerable = true;
return descriptor;
}
class Demo {
foo() {
// do nothing
}
}
__decorate([
Enumerable
], Demo.prototype, "foo", null);
const demo = new Demo();
可以看到编译后的 js 文件中有一个 __decorate
函数,__decorate
函数就是 decorator 的原理。
__decorate
#为了看清楚 __decorate
,将其结构展开,并分析:
var __decorate = (
// 如果 this.__decorate 已经定义,则直接取 this.__decorate
// 这里应该是为以后兼容,如果以后 javascript 已经包含了 __decorate 定义,这里就不需要更改了
(this && this.__decorate)
||
// 如果 this.__decorate 没有定义,则返回下面的函数
// 函数后面三个参数的意义分别是:
// target: 类对象
// key: 方法名称
// desc: 方法的 descriptor
function(decorators, target, key, desc) {
var c = arguments.length,
// 参数个数小于 3,则 r 为 target,
// 参数个数大于3,判断 desc 是否为 null,如果为 null 则将 desc 重新赋值为 descriptor,并将 r 赋值为 descriptor
r = (
c < 3
? target
: (
desc === null
? desc = Object.getOwnPropertyDescriptor(target, key)
: desc
)
),
d;
// 判断 Reflect.decorate 函数是否存在,如果存在,则直接调用 Reflect.decorate 函数
// 实际上 Reflect.decorate 函数还没有实现,所以这里也是为了以后做准备,说不定哪一天 javascript 标准就实现了 Reflect.decorate 函数
if (
typeof Reflect === "object"
&&
typeof Reflect.decorate === "function"
) {
r = Reflect.decorate(decorators, target, key, desc);
} else {
// 根据参数的个数(c),依次执行 decorators 函数
for (var i = decorators.length - 1; i >= 0; i--) {
if (d = decorators[i]) {
r = (
(
c < 3
? d(r)
: (
c > 3
? d(target, key, r)
: d(target, key)
)
)
||
r
);
}
}
}
// 返回结果
return (
c > 3
&&
r
&&
Object.defineProperty(target, key, r),
r
);
}
);
ts 源文件:
function LogParameter(
target: any,
propertyKey: string | symbol,
parameterIndex: number,
) {
console.log(target);
console.log(propertyKey);
console.log(parameterIndex);
}
class ParameterExample {
public logThis(
first: string = "",
@LogParameter greeting: string = "Hello, world",
) {
// do nothing
}
}
const demoParameter = new ParameterExample();
编译后的 js 文件:
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __param = (this && this.__param) || function (paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); }
};
function LogParameter(target, propertyKey, parameterIndex) {
console.log(target);
console.log(propertyKey);
console.log(parameterIndex);
}
class ParameterExample {
logThis(first = "", greeting = "Hello, world") {
// do nothing
}
}
__decorate([
__param(1, LogParameter)
], ParameterExample.prototype, "logThis", null);
const demoParameter = new ParameterExample();
ts 源文件:
function LogProperty(
target: any,
propertyKey: string | symbol,
) {
console.log(target);
console.log(propertyKey);
}
class PropertyExample {
@LogProperty
public greeting: string;
constructor() {
this.greeting = "Hello, world";
}
}
const demoExample = new PropertyExample();
编译后的 js 文件:
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
function LogProperty(target, propertyKey) {
console.log(target);
console.log(propertyKey);
}
class PropertyExample {
constructor() {
this.greeting = "Hello, world";
}
}
__decorate([
LogProperty
], PropertyExample.prototype, "greeting", void 0);
const demoExample = new PropertyExample();
ts 源文件:
function LogClass(target: any) {
console.log(target.constructor.name);
}
@LogClass
class ClassExample {
// do nothing
}
const demoClass = new ClassExample();
编译后的 js 文件:
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
function LogClass(target) {
console.log(target.constructor.name);
}
let ClassExample = class ClassExample {
};
ClassExample = __decorate([
LogClass
], ClassExample);
const demoClass = new ClassExample();
(完)