一文读懂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 相关文章推荐
js类的静态属性和实例属性的理解
Oct 01 Javascript
jQuery中阻止冒泡事件的方法介绍
Apr 12 Javascript
jquery动态添加删除(tr/td)
Feb 09 Javascript
node.js的事件机制
Feb 08 Javascript
javascript实现动态显示颜色块的报表效果
Apr 10 Javascript
微信小程序简单实现form表单获取输入数据功能示例
Nov 30 Javascript
基于Vue的SPA动态修改页面title的方法(推荐)
Jan 02 Javascript
vue中使用heatmapjs的示例代码(结合百度地图)
Sep 05 Javascript
vue.js实现的全选与全不选功能示例【基于elementui】
Dec 03 Javascript
微信小程序从注册账号到上架(图文详解)
Jul 17 Javascript
JavaScript变量Dom对象的所有属性
Apr 30 Javascript
在Vuex中Mutations修改状态操作
Jul 24 Javascript
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使用json_decode后数字对象转换成了科学计数法的解决方法
2017/02/20 PHP
PHP使用SMTP邮件服务器发送邮件示例
2018/08/28 PHP
javascript mouseover、mouseout停止事件冒泡的解决方案
2009/04/07 Javascript
JavaScript获取GridView中用户点击控件的行号,列号
2009/04/14 Javascript
Jquery 基础学习笔记之文档处理
2009/05/29 Javascript
js本身的局限性 别让javascript做太多事
2010/03/23 Javascript
JS生成随机字符串的多种方法
2014/06/10 Javascript
JavaScript数组函数unshift、shift、pop、push使用实例
2014/08/27 Javascript
jQuery中的pushStack实现原理和应用实例
2015/02/03 Javascript
jquery的幻灯片图片切换效果代码分享
2015/09/07 Javascript
jQuery+css实现的蓝色水平二级导航菜单效果代码
2015/09/11 Javascript
Nodejs实战心得之eventproxy模块控制并发
2015/10/27 NodeJs
canvas绘制一个常用的emoji表情
2017/03/30 Javascript
微信小程序实现单选功能
2018/10/30 Javascript
如何在基于vue-cli的项目自定义打包环境
2018/11/10 Javascript
详解Element-UI中上传的文件前端处理
2019/08/07 Javascript
Vue + Node.js + MongoDB图片上传组件实现图片预览和删除功能详解
2020/04/29 Javascript
[42:52]Optic vs Serenity 2018国际邀请赛淘汰赛BO3 第二场 8.22
2018/08/23 DOTA
[01:32:22]DOTA2-DPC中国联赛 正赛 Ehome vs VG BO3 第一场 2月5日
2021/03/11 DOTA
Python实现的插入排序算法原理与用法实例分析
2017/11/22 Python
Python从ZabbixAPI获取信息及实现Zabbix-API 监控的方法
2018/09/17 Python
详解Python requests 超时和重试的方法
2018/12/18 Python
Django框架静态文件使用/中间件/禁用ip功能实例详解
2019/07/22 Python
使用python的turtle绘画滑稽脸实例
2019/11/21 Python
python itsdangerous模块的具体使用方法
2020/02/17 Python
Keras模型转成tensorflow的.pb操作
2020/07/06 Python
python 中的9个实用技巧,助你提高开发效率
2020/08/30 Python
伦敦高级内衣品牌:Agent Provocateur(大内密探)
2016/08/23 全球购物
Bjorn Borg官方网上商店:国际运动时尚品牌
2016/08/27 全球购物
德国网上超市:myTime.de
2019/08/26 全球购物
办公室文员自荐书
2014/02/03 职场文书
《花瓣飘香》教学反思
2014/04/15 职场文书
2015人事行政工作总结范文
2015/05/21 职场文书
放牛班的春天观后感
2015/06/01 职场文书
小学体育组工作总结
2015/08/13 职场文书
导游词之唐山景点
2019/12/18 职场文书