一文读懂ES7中的javascript修饰器


Posted in Javascript onMay 06, 2019

什么是修饰器

修饰器(Decorator)是ES7的一个提案,它的出现能解决两个问题:

  • 不同类间共享方法
  • 编译期对类和方法的行为进行改变

用法也很简单,就是在类或方法的上面加一个@符,在vue in typescript中经常用到

一文读懂ES7中的javascript修饰器

以上的两个用处可能不太明白,没关系,我们开始第一个例子

例子1:修饰类

@setProp
class User {}

function setProp(target) {
 target.age = 30
}

console.log(User.age)

这个例子要表达的是对User类使用setProp这个方法进行修饰,用来增加User类中age的属性,setProp方法会接收3个参数,我们现在接触第一个,target代表User类本身。

例子2:修饰类(自定义参数值)

@setProp(20)
class User {}

function setProp(value) {
 return function (target) {
  target.age = value
 }
}

console.log(User.age)

此例和上面功能基本一致,唯一差别在于值是参考修饰函数传过来的

例子2:修饰方法

class User {
 @readonly
 getName() {
  return 'Hello World'
 }
}

// readonly修饰函数,对方法进行只读操作
function readonly(target, name, descriptor) {
 descriptor.writable = false
 return descriptor
}

let u = new User()
// 尝试修改函数,在控制台会报错
u.getName = () => {
 return 'I will override'
}

上例中,我们对User类中的getName方法使用readonly修饰器进行修饰,使得方法不能被修改。第一个参数我们已经知道了,参数name为方法名,也就是readonly,参数descriptor是个啥东西呢,看到这行descriptor.writable = false,我们大家猜的也差不多了,这三个参数对应的就是Object.defineProperty的三个参数,我们来看一下:

一文读懂ES7中的javascript修饰器

我们设置descriptor.writable = false就是让函数不可以被修改,如果我们写成

descriptor.value = 'function (){ console.log('Hello decorator') }'

那么,输出就是Hello World了,而是Hello decorator,是不是已经意识到修饰器的好处了。现在我们来看看实际工作中,我们用到修饰器的例子

实际应用1:日志管理

在用webpack打包时,我们经常需要好多步骤,比如第一步读取package.json文件,第二步处理该文件,第三步加载webpack.base.js文件,第四步进行打包...为了直观,我们经常在每一步打印一些日志文件,比如这步都干了些什么事,很明显打印日志的操作和业务代码根本就一点关系没有,我们不应该把日志和业务掺和在一起,这样使用修饰器就是避免这个问题,以下为代码:

class Pack {
 @log('读取package.json文件')
 step1() {
  // do something...
  // 没有修饰器之前,我们通常把console.log放到这里写
  // 放到函数里面写会有两个坏处
  //  1.console和业务无关,会破坏函数单一性原则
  //  2.如果要删除所有的console,那我们只能深入到每一个方法中
 }
 @log('合并webpack配置文件')
 step2() {
  // do something...
 }
}

function log(value) {
 return function (target, name, descriptor) {
  // 在这里,我们还可以拿到函数的参数,打印更加详细的信息
  console.log(value)
 }
}

let pack = new Pack()
pack.step1()
pack.step2()

实际应用2:检查登录

这个例子在实际的开发中常用得到,我们一些操作前,必须得判断用户是否登录,比较点赞、结算、发送弹幕...按照之前的写法,我们必须在每一个方法中判断用户的登录情况,然后再进行业务的操作,很显然前置条件和业务又混到了一起,用修饰器,就可以完美的解决这一问题,代码如下:

class User {
 // 获取已登录用户的用户信息
 @checkLogin
 getUserInfo() {
  /**
   * 之前,我们都会这么写:
   *  if(checkLogin()) {
   *   // 业务代码
   *  }
   * 这段代码会在每一个需要登录的方法中执行
   * 还是上面的问题,执行的前提和业务又混到了一起
   */
  console.log('获取已登录用户的用户信息')
 }
 // 发送消息
 @checkLogin
 sendMsg() {
  console.log('发送消息')
 }
}

// 检查用户是否登录,如果没有登录,就跳转到登录页面
function checkLogin(target, name, descriptor) {
 let method = descriptor.value

 // 模拟判断条件
 let isLogin = true

 descriptor.value = function (...args) {
  if (isLogin) {
   method.apply(this, args)
  } else {
   console.log('没有登录,即将跳转到登录页面...')
  }
 }
}
let u = new User()
u.getUserInfo()
u.sendMsg()

结语

以上只是修饰器的基本应用,只要我们掌握了原理,在实际的工作中,要思考自己的应用场景,只要我们涉及需要在执行前做一些处理的应用,不管是修改函数的参数值,还是增加属性,还是执行的先决条件,我们都可以使用修饰器,这种编程的方式,就是面向切面编程

源码以及使用方法,请移步GitHub(本地下载)

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
用jscript实现新建和保存一个word文档
Jun 15 Javascript
dropdownlist之间的互相联动实现(显示与隐藏)
Nov 24 Javascript
getElementByIdx_x js自定义getElementById函数
Jan 24 Javascript
select标签模拟/美化方法采用JS外挂式插件
Apr 01 Javascript
JavaScript使用function定义对象并调用的方法
Mar 23 Javascript
JS实现在状态栏显示打字效果完整实例
Nov 02 Javascript
JavaScript缓冲运动实现方法(2则示例)
Jan 08 Javascript
详解JavaScript模块化开发
Dec 04 Javascript
深入理解Angularjs中的$resource服务
Dec 31 Javascript
写jQuery插件时的注意点
Feb 20 Javascript
vue实现重置表单信息为空的方法
Sep 29 Javascript
Vuex实现简单购物车
Jan 10 Vue.js
JavaScript中AOP的实现与应用
May 06 #Javascript
使用 vue 实现灭霸打响指英雄消失的效果附demo
May 06 #Javascript
vue如何截取字符串
May 06 #Javascript
用vscode开发vue应用的方法步骤
May 06 #Javascript
微信小程序合法域名配置方法
May 06 #Javascript
手把手教你使用TypeScript开发Node.js应用
May 06 #Javascript
微信小程序上线发布流程图文详解
May 06 #Javascript
You might like
php通过array_merge()函数合并两个数组的方法
2015/03/18 PHP
php的闭包(Closure)匿名函数初探
2016/02/14 PHP
基于php解决json_encode中文UNICODE转码问题
2020/11/10 PHP
js获取客户端外网ip的简单实例
2013/11/21 Javascript
Javascript中的Array数组对象详谈
2014/03/03 Javascript
js判断当前页面用什么浏览器打开的方法
2016/01/06 Javascript
基于BootStrap的图片轮播效果展示实例代码
2016/05/23 Javascript
Node.js + Redis Sorted Set实现任务队列
2016/09/19 Javascript
jquery判断类型是不是number类型的实例代码
2016/10/07 Javascript
老生常谈js数据类型
2017/08/03 Javascript
javascript计算渐变颜色的实例
2017/09/22 Javascript
react.js 父子组件数据绑定实时通讯的示例代码
2017/09/25 Javascript
axios post提交formdata的实例
2018/03/16 Javascript
详解elementui之el-image-viewer(图片查看器)
2019/08/30 Javascript
关于vue 结合原生js 解决echarts resize问题
2020/07/26 Javascript
[40:31]Secret vs Alliacne 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
[57:09]DOTA2-DPC中国联赛 正赛 Phoenix vs Dynasty BO3 第一场 1月26日
2021/03/11 DOTA
python 随机数生成的代码的详细分析
2011/05/15 Python
python安装以及IDE的配置教程
2015/04/29 Python
Python实现的井字棋(Tic Tac Toe)游戏示例
2018/01/31 Python
在CMD命令行中运行python脚本的方法
2018/05/12 Python
对python:print打印时加u的含义详解
2018/12/15 Python
python解析含有重复key的json方法
2019/01/22 Python
Python何时应该使用Lambda函数
2019/07/02 Python
Django实现微信小程序的登录验证功能并维护登录态
2019/07/04 Python
python 根据字典的键值进行排序的方法
2019/07/24 Python
python中的Elasticsearch操作汇总
2019/10/30 Python
Python实现子类调用父类的初始化实例
2020/03/12 Python
Pyqt5 关于流式布局和滚动条的综合使用示例代码
2020/03/24 Python
Django 5种类型Session使用方法解析
2020/04/29 Python
CSS3中的Transition过度与Animation动画属性使用要点
2016/05/20 HTML / CSS
技校毕业生自荐书
2014/05/23 职场文书
安全生产知识竞赛活动总结
2014/07/07 职场文书
2016年中学清明节活动总结
2016/04/01 职场文书
整理Python中常用的conda命令操作
2021/06/15 Python
Nginx隐藏式跳转(浏览器URL跳转后保持不变)
2022/04/07 Servers