内容简介:原文链接:目前 JavaScript 的装饰器处于提案 Stage-2 阶段,且尚未稳定。因此与所有提案一样,在未来可能会发生变化。本文为个人的思考和见解,如有异议欢迎拍砖。装饰器这个概念想必大家并不陌生,笔者最早遇到这个词是在学习 Java 的时候,主要应用是在 Java 的 Spring 中,其中有个概念叫 AOP(面向切面编程)。
原文链接: QC-L/blog
目前 JavaScript 的装饰器处于提案 Stage-2 阶段,且尚未稳定。因此与所有提案一样,在未来可能会发生变化。本文为个人的思考和见解,如有异议欢迎拍砖。
装饰器这个概念想必大家并不陌生,笔者最早遇到这个词是在学习 Java 的时候,主要应用是在 Java 的 Spring 中,其中有个概念叫 AOP(面向切面编程)。
当然这个概念在 JavaScript 中也已有其他的应用,比如 TypeScript,MobX 等。社区也有 Redux 相关的解决方案,如 @connect 装饰器的使用。
这里给大家带来的是有关 Babel 7.1.0 中实现的 @babel/babel-plugin-proposal-decorators
相关应用。
环境搭建
由于该提案依赖于 Babel 的提案插件,因此需要搭建一个简易的 Babel 编译环境。
新建目录,初始化 package.json:
$ mkdir test-decorator && cd test-decorator $ npm init -y 复制代码
在 package.json 中添加 Babel 相关 package:
yarn add -D @babel/cli @babel/core @babel/preset-env 复制代码
创建 .babelrc
touch .babelrc 复制代码
添加如下配置:
{ "presets": ["@babel/preset-env"] } 复制代码
在目录中添加 src/index.js
:
class TestDecorator { method() {} } 复制代码
在 package.json
中添加 build script 命令
{ "name": "test-decorator", "version": "1.0.0", "description": "", "main": "src/index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", + "build": "babel src -d dist" }, "author": "", "license": "ISC", "devDependencies": { "@babel/cli": "^7.2.3", "@babel/core": "^7.2.2", "@babel/preset-env": "^7.3.1" } } 复制代码
创建 index.html 文件,并引入 dist/index.js
:
<!doctype html> <html> <head> <title>测试</title> </head> <body> <script src="./dist/index.js"></script> </body> </html> 复制代码
执行 yarn build
即可。
装饰器初窥
1.编写一个类装饰器函数
修改 src/index.js:
class TestDecorator { method() {} } // 类装饰器函数 function decorator(value) { return function(classDescriptor) { console.log(classDescriptor); } } 复制代码
2.使用类装饰器
+ @decorator class TestDecorator { method() {} } 复制代码
3.安装 Babel 插件,并修改 .babelrc 文件:
$ yarn add -D @babel/plugin-proposal-decorators 复制代码
{ "presets": ["@babel/preset-env"], + "plugins": [ + ["@babel/plugin-proposal-decorators", { + "decoratorsBeforeExport": true // 用于标识装饰器所处位置(提案中讨论的点) + }] + ] } 复制代码
注: decoratorsBeforeExport
是必需设置的选项,否则会抛出异常。为 true
时,会修饰在 export class 上方;为 false
时,会修饰在 export class 前。
// decoratorsBeforeExport: false export @decorator class TestDecorator {} // decoratorsBeforeExport: true @decorator export class TestDecorator {} 复制代码
如不设置 decoratorsBeforeExport
异常如下:
Error: [BABEL] /test-decorator/src/index.js: The decorators plugin requires a 'decoratorsBeforeExport' option, whose value must be a boolean. If you want to use the legacy decorators semantics, you can set the 'legacy: true' option. (While processing: "/test-decorator/node_modules/@babel/plugin-proposal-decorators/lib/index.js") 复制代码
4.执行 yarn build
,打开 index.html 查看控制台结果。
装饰器参数详解
装饰器修饰的位置不同,所得的参数有所不同。并且有参数的装饰器与无参数的装饰器也有所区别。 装饰器可修饰内容如下:
- class
- class method
- class fields
调用装饰器时,参数结构对比如下:
-
修饰 class
与 TypeScript 以前之前的装饰器的区别在于,声明的装饰器方法的参数,为 Descriptor 类型。
参数 值 说明 kind class 标识,用于说明当前修饰的内容 elements [Descriptor] 描述符组成的数组,描述类中所有的元素 其中 elements 中对象与 method 和 fields 相同,后面介绍。
-
修饰 class method和 修饰 class fields
参数 说明 method fields kind 标识,用于说明当前修饰的内容 method field descriptor 与 Object.defineProperty 中的 descriptor 相同 [object Object] [object Object] key 所修饰的 method 或 fileds 的名称。可以是 String,Symbol 或 Private Name method x placement 可选的参数为 "static","prototype" 或者 "own" prototype | static | own
prototype | static | own
其中关于 key 的描述,在提案中有这么一段。
For private fields or accessors, the
key
will be a Private Name--this is similar to a String or Symbol, except that it is invalid to use with property access[]
or with operations such asObject.defineProperty
. Instead, it can only be used with decorators.可能有些小伙伴未了解过 Object.defineProperty,这里针对 descriptor 介绍下其包含哪些属性:
参数 值 说明 默认值 configurable true 当且仅当该属性的 configurable 为 true 时,该属性描述符才能够被改变,同时该属性也能从对应的对象上被删除 false enumerable false 当且仅当该属性的enumerable为true时,该属性才能够出现在对象的枚举属性中 false value method 该属性对应的值。可以是任何有效的 JavaScript 值(数值,对象,函数等) undefined writable true 当且仅当该属性的writable为true时,value才能被赋值运算符改变。 false get undefined 当且仅当该属性的writable为true时,value才能被赋值运算符改变。 undefined set undefined 一个给属性提供 setter 的方法,如果没有 setter 则为 undefined。当属性值修改时,触发执行该方法。该方法将接受唯一参数,即该属性新的参数值。 undefined 注意: 如果一个描述符不具有 value, writable, get 和 set 任意一个关键字,那么它将被认为是一个数据描述符。如果一个描述符同时有 (value 或 writable) 和 (get 或 set) 关键字,将会产生一个异常
如想尝试的可以自己打印一下, Demo 地址 。
示例
@classDecoratorArgs(function () {}) @classDecorator class TestDecorator { @filedsDecoratorArgs('fileds') @filedsDecorator x = 10 // 注意,如果要在 class 中使用 fileds 需要额外引用 @babel/plugin-proposal-class-properties @methodDecoratorArgs(20) @methodDecorator method() {} } // 无参数 class decorator function classDecorator(classDescriptor) { console.log(classDescriptor); } // 无参数 fileds decorator function filedsDecorator(filedsDescriptor) { console.log(filedsDescriptor); } // 无参数 method decorator function methodDecorator(elementDescriptor) { console.log(elementDescriptor); } // 有参数 class decorator function classDecoratorArgs(args) { console.log(args); return function(classDescriptor) { console.log(classDescriptor); } } // 有参数 fileds decorator function filedsDecoratorArgs(args) { console.log(args); return function(filedsDescriptor) { console.log(filedsDescriptor); } } // 有参数 method decorator function methodDecoratorArgs(args) { console.log(args); return function(elementDescriptor) { console.log(elementDescriptor); } } 复制代码
以上所述就是小编给大家介绍的《【小试牛刀】Stage-2 装饰器初探》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 装饰器与元数据反射(1)方法装饰器
- 草根学Python(十六) 装饰器(逐步演化成装饰器)
- 一文读懂 JS 装饰器,这是一个会打扮的装饰器
- 装饰器与元数据反射(2)属与类性装饰器
- Python装饰器
- python--装饰器详解
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。