许多面向对象都有decorator(装饰器)函数,比如python中也可以用decorator函数来强化代码,decorator相当于一个高阶函数,接收一个函数,返回一个被装饰后的函数。

注: javascript中也有decorator相关的提案,只是目前node以及各浏览器中均不支持。只能通过安装babel插件来转换代码,插件名叫这个:transform-decorators-legacy。也有在线试用](https://babeljs.io/repl/
),安装好transform-decorators-legacy之后,就能看到转义后的代码了:

npm i -D @babel/plugin-proposal--decorators

可以再下载一个plugin配置类里面属性的写法

npm i -D @babel/plugin-proposal-class-properties

在babelrc中配置插件:

options: {plugins: ['@babel/plugin-proposal-class-properties']
}

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) // laser

上面代码中,@transform就是一个修饰器。它修改了IronMan这个类的行为,为它加上了武器属性weapontransform函数的参数targetIronMan类本身。

2.方法的修饰

修饰器不仅可以修饰类,还可以修饰类的属性。

class Person {@readonlyname() { 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;
}
Person.prototype.name="韩梅梅"
console.log(Person.prototype.name)//fn 修饰的是类的原型
​
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; // 具体三个方法let result = method()console.log(`${type}${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 {@readonlyentree (){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 {@overridespeak() {}// SyntaxError: Child#speak() does not properly override Parent#speak(first, second)
}
​
// or
​
class Child extends Parent {@overridespeaks() {}// SyntaxError: No descriptor matching Child#speaks() was found on the prototype chain.////   Did you mean "speak"?
}

(3)@deprecate (别名@deprecated)

deprecatedeprecated修饰器在控制台显示一条警告,表示该方法将废除。

import { deprecate } from 'core-decorators';
​
class Person {@deprecatefacepalm() {}
​@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.
//

decorator 装饰器相关推荐

  1. 一文读懂 @Decorator 装饰器——理解 VS Code 源码的基础

    作者:easonruan,腾讯 CSIG 前端开发工程师 1. 装饰器的样子 我们先来看看 Decorator 装饰器长什么样子,大家可能没在项目中用过 Decorator 装饰器,但多多少少会看过下 ...

  2. Python 中的闭包、匿名函数、decorator 装饰器与python的偏函数

    Python中的闭包 def calc_sum(lst):def lazy_sum():return sum(lst)return lazy_sum 像这种内层函数引用了外层函数的变量(参数也算变量) ...

  3. JS Decorator —— 装饰器(装饰模式)

    本文只浅析类装饰器和方法装饰器,其他原理相似,暂不赘述. 关于@Component类装饰器及vue-class-component源码可查看本人另一篇:源码探秘之 vue-class-componen ...

  4. Python中的decorator装饰器使用方法

    装饰器的运用是Python编程中的一项高级技巧,这里由浅入深,整理了12步入门Python中的decorator装饰器使用方法,需要的朋友可以参考下 装饰器(decorator)是一种高级Python ...

  5. 聊聊在Vue项目中使用Decorator装饰器

    戳蓝字" Web前端严选 " 关注我们哦 ! 前言 初衷: 前几天我在公司其它Vue项目中,发现了是用Decorator装饰器模式开发的,看起来整体代码还不错,于是就做了一下笔记分 ...

  6. Java —— Decorator 装饰器模式

    文章目录 Java -- Decorator 装饰器模式 简介 用处 简单例子 结构 代码 涉及角色 相关的设计模式 应用实例 优点 缺点 使用场景 注意事项 代码 Java -- Decorator ...

  7. Decorator 装饰器模式 -动态组合

    为什么80%的码农都做不了架构师?>>>    一:业务场景 奖金计算,每个部门,有不同的计算方法,且每个部门有不同类型的奖金项:而且每年或每隔几个季度奖金算法都要重新实现下. 这个 ...

  8. Python进阶: Decorator 装饰器你太美

    函数 -> 装饰器 函数的4个核心概念 1.函数可以赋与变量 def func(message):print('Got a message: {}'.format(message))send_m ...

  9. 使用 sitemesh/decorator装饰器装饰jsp页面(原理及详细配置)

    摘要:首先这个Decorator解释一下这个单词:"装饰器",我觉得其实可以这样理解,他就像我们用到的Frame,他把每个页面共有的东西提炼了出来,也可能我们也会用各种各样的inc ...

最新文章

  1. java订单实现的_java订单系统的开发
  2. Nature | 有机合成的数字化
  3. 查看SQL Server Resource Database以及修改系统表
  4. Linux的centos永久关闭防火墙的命令
  5. (巴什博弈 sg函数入门1) Brave Game -- hdu -- 1846
  6. Oracle-逻辑体系结构
  7. java构造器_Java构造器就是这么简单!
  8. linux安装之后缺少命令,centos7下安装缺少的命令依赖包
  9. 《Python编程从入门到实践》记录之第7章 用户输入(input)和while 循环总结(思维导图)
  10. python 图形_Python切分图像小案例(1、3、2、4象限子图互换)
  11. Mysql的可视化工具整理
  12. 如何清洁Mac的屏幕
  13. 用putty连接虚拟机下ubuntu ssh
  14. matlab命令窗口作用是什么,wcodemat这个命令在matlab中是实现什么功能的
  15. 【Nape教程】认识Nape空间
  16. 1. PYNQ在ZCU102上的移植【PYNQ】
  17. ModelSim仿真入门之一:软件介绍
  18. 自己写的uvc驱动支持IP2977/ip2970
  19. 二级列表ExpandableListView的CheckBox使用
  20. 苹果手机基带坏了怎么办

热门文章

  1. 微擎支付返回商户单号_微信、支付宝支付动态库PayApiFun.dll说明
  2. TC118S单通道内置MOS单通道直流无刷马达驱动IC
  3. TFT-LCD显示驱动系统架构
  4. Qt USB HID通讯
  5. IAR环境下中断控制
  6. 基于CentOS平台的Snort+Barnyard安装步骤
  7. 哈希函数-MD5算法
  8. IT牛人的博客地址——收藏
  9. r9 5900hx和i7 10870h哪个好
  10. 【题解】玲珑杯河南专场17B