es6 js装饰器decorator的使用 +webpack4.0配置decorator
栏目: JavaScript · 发布时间: 5年前
内容简介:注: javascript中也有在vscode里打开设置=>用户设置里面加入(tips:打开设置后也可以直接点击右上角的'{}'进行用户设置)就可以了;
许多面向对象都有decorator(装饰器)函数,比如 python 中也可以用decorator函数来强化代码,decorator相当于一个高阶函数,接收一个函数,返回一个被装饰后的函数。
注: javascript中也有 decorator
相关的提案,只是目前node以及各浏览器中均不支持。只能通过安装babel插件来转换代码,插件名叫这个: transform-decorators-legacy
。也有在线试用](babeljs.io/repl/),安装好 transform-decorators-legacy
之后,就能看到转义后的代码了
2.1 使用decorator的前期配置
1.vscode里面去除装饰器报错的方法
在vscode里打开设置=>用户设置里面加入(tips:打开设置后也可以直接点击右上角的'{}'进行用户设置)
"javascript.implicitProjectConfig.experimentalDecorators": true 复制代码
就可以了;
2.搭建一个简单的webpack 来使用装饰器
由于目前浏览器和node暂时不支持装饰器,所以我们可以配置一个webpack来使用装饰器
全局安装
cnpm install webpack webpack-cli webpack-dev-server -g 复制代码
启动配置 创建一个webpack.dev.js
var path = require('path') module.exports = { mode: "development", entry: { main: "./test.js" }, output: { path: path.resolve(__dirname, "./dist"), filename: "test.js" }, module: { rules: [ //webpack 4.X写法 { test: /.js$/, use: ['babel-loader'] } ] } } 复制代码
下载依赖(webpack4.x 方法 )
npm install -D babel-loader @babel/core @babel/preset-env 复制代码
配置.babelrc
{ "presets": [ "@babel/preset-env" ], "plugins": [ [ "@babel/plugin-proposal-decorators", { "legacy": true } ], ] } 复制代码
创建好webpack的目录结构是这样的
package.json的配置
{ "name": "decorator", "version": "1.0.0", "description": "", "main": "test.js", "scripts": { "build": "webpack --config=webpack.dev.js", "start": "node ./dist/bound.js" }, "keywords": [], "author": "", "license": "ISC", "dependencies": { "@babel/core": "^7.4.4", "@babel/plugin-proposal-class-properties": "^7.4.4", "@babel/plugin-proposal-decorators": "^7.4.4", "@babel/preset-env": "^7.4.4", "babel-loader": "^8.0.5", "babel-plugin-transform-decorators-legacy": "^1.3.5", "babel-preset-env": "^1.7.0", "core-decorators": "^0.20.0" } } 复制代码
2.2 开始使用decorator
1.类的修饰
许多面向对象的语言都有修饰器(Decorator)函数,用来修改类的行为。目前,有一个 提案 将这项功能,引入了 ECMAScript。
@transform class IronMan { // ... } function transform(target) { target.weapon = laser } console.log(IronMan.weapon) // true 复制代码
上面代码中,@transform就是一个修饰器。它修改了 IronMan
这个类的行为,为它加上了武器属性 weapon
。 transform
函数的参数 target
是 IronMan
类本身。
2.结合redux库使用
实际开发中,React 与 Redux 库结合使用时,常常需要写成下面这样。
class MyReactComponent extends React.Component {} export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent); 复制代码
有了装饰器,就可以改写上面的代码。
@connect(mapStateToProps, mapDispatchToProps) export default class MyReactComponent extends React.Component {} 复制代码
3.方法的修饰
修饰器不仅可以修饰类,还可以修饰类的属性。
class Person { @readonly name() { return `${this.first} ${this.last}` } } 复制代码
上面代码中,修饰器 readonly
用来修饰“类”的 name
方法。
修饰器函数 readonly
一共可以接受三个参数。
function readonly(target, name, descriptor){ // descriptor对象原来的值如下 // { // value: specifiedFunction, // enumerable: false, // configurable: true, // writable: true // }; descriptor.writable = false; return descriptor; } readonly(Person.prototype, 'name', descriptor); // 类似于 Object.defineProperty(Person.prototype, 'name', descriptor); 复制代码
修饰器第一个参数是类的原型对象,上例是 Person.prototype
,修饰器的本意是要“修饰”类的实例,但是这个时候实例还没生成,所以只能去修饰原型(这不同于类的修饰,那种情况时 target
参数指的是类本身);第二个参数是所要修饰的属性名,第三个参数是该属性的描述对象。
4.装饰器不能用于修饰函数
原本作者设计的时候 是可以使用这种方式的 比如修饰一个函数这么写
@RunOnce function expensiveOperation() { return 1 + 1; } //语法糖之后的效果是这样的 var expensiveOperation = RunOnce(function expensiveOperation() { return 1 + 1; }); 复制代码
这意味着装饰器可以用于任何任务,但是作者认为这样可能有点复杂 并且还有一个潜在的问题 装饰器和跟随变量一块提升 使得装饰器语法函数过早执行而导致因为位置的原因产生的一些错误 比如:
var readOnly = require("some-decorator"); // 是否提升求值? // 如果是这样的话 `readOnly` 那么就是未定义 @readOnly function foo() { } 复制代码
总而言之,作者不希望产生这样的复杂性,所以去除了修饰函数,详情可以参考这篇作者参与讨论的 帖子
5.应用
至于decorator的应用场景在哪里?应该大部分AOP的场景都可以用,例如日志系统。 这里就手动来实现一个简单的日志系统。
const log = (type) => { return (target, name, descriptor) => { let method = descriptor.value ; // 具体三个方法 descriptor.value = (...args) => { console.log(`${type}`); let result ; try { result = method.apply(target,args); console.log(`${type} ${result} 成功`) } catch (error) { console.log(`${type} ${result} 失败`) } return result ; } } } class Man { @log('正在洗漱') wash() { return "洗漱"; } @log('正在吃饭') eat() { return "吃饭"; } @log('正在跑步') run() { return "跑步"; } } let m = new Man() ; m.wash(); m.eat(); m.run(); 复制代码
####6.core-decorators.js
core-decorators.js 是一个第三方模块,提供了几个常见的修饰器,通过它可以更好地理解修饰器。
(1)@readonly
readonly
修饰器使得属性或方法不可写。
import { readonly } from 'core-decorators'; class Meal { @readonly entree (){ console.log(111) }; } var dinner = new Meal(); dinner.entree = 'salmon'; // Cannot assign to read only property 'entree' of [object Object] 复制代码
(2)@override
override
修饰器检查子类的方法,是否正确覆盖了父类的同名方法,如果不正确会报错。
import { override } from 'core-decorators'; class Parent { speak(first, second) {} } class Child extends Parent { @override speak() {} // SyntaxError: Child#speak() does not properly override Parent#speak(first, second) } // or class Child extends Parent { @override speaks() {} // SyntaxError: No descriptor matching Child#speaks() was found on the prototype chain. // // Did you mean "speak"? } 复制代码
(3)@deprecate (别名@deprecated)
deprecate
或 deprecated
修饰器在控制台显示一条警告,表示该方法将废除。
import { deprecate } from 'core-decorators'; class Person { @deprecate facepalm() {} @deprecate('We stopped facepalming') facepalmHard() {} @deprecate('We stopped facepalming', { url: 'http://knowyourmeme.com/memes/facepalm' }) facepalmHarder() {} } let person = new Person(); person.facepalm(); // DEPRECATION Person#facepalm: This function will be removed in future versions. person.facepalmHard(); // DEPRECATION Person#facepalmHard: We stopped facepalming person.facepalmHarder(); // DEPRECATION Person#facepalmHarder: We stopped facepalming // // See http://knowyourmeme.com/memes/facepalm for more details. // 复制代码
(4)@suppressWarnings
suppressWarnings
修饰器抑制 deprecated
修饰器导致的 console.warn()
调用。但是,异步代码发出的调用除外。
import { suppressWarnings } from 'core-decorators'; class Person { @deprecated facepalm() {} @suppressWarnings facepalmWithoutWarning() { this.facepalm(); } } let person = new Person(); person.facepalmWithoutWarning(); // no warning is logged 复制代码
####7.Mixin
在修饰器的基础上,可以实现 Mixin
模式。所谓 Mixin
模式,就是对象继承的一种替代方案,中文译为“混入”(mix in),意为在一个对象之中混入另外一个对象的方法。
const Foo = { foo() { console.log('foo') } }; class MyClass {} Object.assign(MyClass.prototype, Foo); let obj = new MyClass(); obj.foo() // 'foo' 复制代码
可以使用装饰器改写为
function mixins(...list) { return function (target) { Object.assign(target.prototype, ...list); }; } const Foo = { foo() { console.log('foo') } }; @mixins(Foo) class MyClass {} let obj = new MyClass(); obj.foo() // "foo" 复制代码
这中方法会改写Myclass的 prototype,所以也可以使用继承的方法混入
let MyMixin = (superclass) => class extends superclass { foo() { console.log('foo from MyMixin'); } }; class MyClass extends MyMixin(MyBaseClass) { /* ... */ } let c = new MyClass(); c.foo(); // "foo from MyMixin" 复制代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:- React复习进阶 - 高阶组件的使用/配置装饰品模式/新版context的使用
- 装饰器与元数据反射(1)方法装饰器
- 草根学Python(十六) 装饰器(逐步演化成装饰器)
- 一文读懂 JS 装饰器,这是一个会打扮的装饰器
- 装饰器与元数据反射(2)属与类性装饰器
- Python装饰器
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
代码整洁之道:程序员的职业素养
罗伯特·C.马丁 (Robert C.Martin) / 余晟、章显洲 / 人民邮电出版社 / 2016-9-1 / 49.00元
1. 汇聚编程大师40余年编程生涯的心得体会 2. 阐释软件工艺中的原理、技术、工具和实践 3. 助力专业软件开发人员具备令人敬佩的职业素养 成功的程序员在以往的工作和生活中都曾经历过大大小小的不确定性,承受过永无休止的压力。他们之所以能够成功,是因为拥有一个共同点,都深切关注创建软件所需的各项实践。他们将软件开发视为一种需要精雕细琢加以修炼的技艺,他们以专业人士的标准要求自己,......一起来看看 《代码整洁之道:程序员的职业素养》 这本书的介绍吧!