详解es6超好用的语法糖Decorator


Posted in Javascript onAugust 01, 2018

Decorator(修饰器/装饰器)是es6提出的语法糖,用于修改类的行为。不过目前主流浏览器都没有很好的支持,我们需要用babel来转换为浏览器能识别的语言。在这篇文章中将介绍decorator的基础用法和一些应用实例。

1.修饰类

(1) 基础用法

@testable
class MyClass{}

function testable(target){
  target.isTestable=true
}

console.log(MyClass.isTestable) // true

贴一下babel转换后的代码,

var _class;

let MyClass = testable(_class = class MyClass {}) || _class;

function testable(target) {
  target.isTestable = true;
}

也可以在prototype上修改属性,也可以为修饰器添加多个参数。

@testable(false)
class MyAnotherClass{
  
}
function testable(status){
  return target=>{target.prototype.isTestable=status}
}
console.log('MyClass.isTestable',MyAnotherClass.prototype.isTestable) // false

当然我们通过修饰器,把某个对象的方法添加到目标类的实例上,注意要在类的prototype上添加。

const foo={isTestable:true}
function testable(...list){
  return target=>{Object.assign(target.prototype,...list)}
}

@testable(foo)
class MyAnotherClass{}
const obj=new MyAnotherClass()

console.log('MyClass.isTestable',obj.isTestable) // true

(2) 应用

React App的开发中,使用redux通常需要react-redux中的connect方法,将两者结合在一起。通常的写法是:

class MyReactComponent extends React.Component {}

export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);

如果使用decorator,代码可读性更高了一些。

@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}

2.修饰方法

(1).基础用法

// target:在方法中的target指向类的prototype
function readonly(target,key,descriptor){
  descriptor.writable=false
  return descriptor
}

class MyClass{
  @readonly
  print(){console.log(`a:${this.a}`)}
}

(2).js中Object的属性

var person = {}
Object.defineProperty(person,'name',{
  configurable:false,//能否使用delete、能否需改属性特性、或能否修改访问器属性、,false为不可重新定义,默认值为true
  enumerable:false,//对象属性是否可通过for-in循环,flase为不可循环,默认值为true
  writable:false,//对象属性是否可修改,flase为不可修改,默认值为true
  value:'xiaoming' //对象属性的默认值,默认值为undefined
});

对应到descriptor为下面四个属性:

{
   value: specifiedFunction,
   enumerable: false,
   configurable: true,
   writable: true
};

(3). 应用

我们开始写一个@log修饰器,可以输出日志:

class Math{
  @log
  add(a,b){
    return a+b
  }
}

const math=new Math()
math.add(1,2)

function log(target,name,descriptor){
  const oldValue=descriptor.value

  descriptor.value=function(){
    console.log(`calling ${name} with ${JSON.stringify(arguments)}`)
    return oldValue.apply(this,arguments)
  }

  return descriptor
}

上面的代码中,@log作用是在返回结果前,打印函数名和其参数,起到输出日至的作用。上面的程序运行后,控制台将输出:

calling add with {"0":1,"1":2}

(4). 多个修饰器

良好命名的修饰器可以起到简洁注释的作用,如下:

class Example {
  @readonly
  @enumable
  method(){}
}

多个修饰器的执行顺序是由外向内进入;再由内向外执行。

class Example {
  @decorator(1)
  @decorator(2)
  method(){}
}

function decorator(id){
  console.log('id is ',id)
  return (target,property,descriptor)=>console.log('executed',id)
}

控制台输出

id is  1
id is  2
executed 2
executed 1

附录:babel配置

babel插件transform-decorators还没有正式版,我们可以用transform-decorators-legacy

安装babel

yarn add babel-plugin-transform-decorators-legacy babel-preset-es2017

配置.babelrc

{
  "presets": ["es2017"],
  "plugins":[
    "transform-decorators-legacy"
  ]
}

执行编译后的文件

因为我们为了测试,没必要非得放在浏览器里看了,可以用node执行babel转换后的文件。直接运行yarn start

// package.json

 "scripts": {
  "build": "babel ./decorator -d lib",
  "start":"yarn build && node ./lib/index.js"
 },

参考链接

ECMAScript 6 入门 -- 修饰器

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
window.open的功能全解析
Oct 10 Javascript
JavaScript 实现模态对话框 源代码大全
May 02 Javascript
jQuery EasyUI 中文API Button使用实例
Apr 14 Javascript
目前流行的JavaScript库的介绍及对比
Sep 29 Javascript
微信JS接口大全
Aug 25 Javascript
js实现图片旋转 js滚动鼠标中间对图片放大缩小
Jul 05 Javascript
详解用node搭建简单的静态资源管理器
Aug 09 Javascript
微信小程序车牌号码模拟键盘输入功能的实现代码
Nov 11 Javascript
JS简单判断是否在微信浏览器打开的方法示例
Jan 08 Javascript
Vue-cli3.X使用px2 rem遇到的问题及解决方法
Aug 08 Javascript
在Vue中使用Viser说明(基于AntV-G2可视化引擎)
Oct 28 Javascript
vue报错function () { [native code] },无法出现我们想要的内容 Unknown custom element
Apr 11 Vue.js
Vue Router去掉url中默认的锚点#
Aug 01 #Javascript
vue定义全局变量和全局方法的方法示例
Aug 01 #Javascript
node.js遍历目录的方法示例
Aug 01 #Javascript
深入浅出理解JavaScript闭包的功能与用法
Aug 01 #Javascript
Angular路由ui-router配置详解
Aug 01 #Javascript
javascript数据结构之多叉树经典操作示例【创建、添加、遍历、移除等】
Aug 01 #Javascript
JavaScript事件冒泡与事件捕获实例分析
Aug 01 #Javascript
You might like
DOTA2 玩家自创拉野攻略 特色英雄快速成长篇
2020/04/20 DOTA
坏狼的PHP学习教程之第2天
2008/06/15 PHP
php修改时间格式的代码
2011/05/29 PHP
php中防止伪造跨站请求的小招式
2011/09/02 PHP
解析php中eclipse 用空格替换 tab键
2013/06/24 PHP
PHP提示Deprecated: mysql_connect(): The mysql extension is deprecated的解决方法
2014/08/28 PHP
php异常处理捕获错误整理
2019/09/23 PHP
基于jquery1.4.2的仿flash超炫焦点图播放效果
2010/04/20 Javascript
js 金额文本框实现代码
2012/02/14 Javascript
关于js中alert弹出窗口文本换行问题简单详细说明
2012/12/11 Javascript
javascript数组去重方法终极总结
2014/06/05 Javascript
JavaScript支持的最大递归调用次数分析
2014/06/24 Javascript
jQuery中index()方法用法实例
2014/12/27 Javascript
javascript计时器编写过程与实现方法
2016/02/29 Javascript
详解使用JS如何制作简单的ASCII图与单极图
2017/03/31 Javascript
Node.js 利用cheerio制作简单的网页爬虫示例
2018/03/01 Javascript
Angular开发实践之服务端渲染
2018/03/29 Javascript
jQuery添加新内容的四个常用方法分析【append,prepend,after,before】
2019/03/19 jQuery
Nuxt.js的路由跳转操作(页面跳转nuxt-link)
2020/11/06 Javascript
[01:04:14]VP vs TNC 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
在Heroku云平台上部署Python的Django框架的教程
2015/04/20 Python
python opencv 直方图反向投影的方法
2018/02/24 Python
python如何通过twisted实现数据库异步插入
2018/03/20 Python
用Python实现读写锁的示例代码
2018/11/05 Python
使用Python的toolz库开始函数式编程的方法
2018/11/15 Python
django orm 通过related_name反向查询的方法
2018/12/15 Python
如何用Python破解wifi密码过程详解
2019/07/12 Python
详解如何从TensorFlow的mnist数据集导出手写体数字图片
2019/08/05 Python
python Matplotlib基础--如何添加文本和标注
2021/01/26 Python
css3简单练习实现遨游浏览器logo的绘制
2013/01/30 HTML / CSS
巧用CSS3的calc()宽度计算做响应模式布局的方法
2018/03/22 HTML / CSS
学生自我鉴定范文
2013/10/04 职场文书
初中学校军训方案
2014/05/09 职场文书
2015年幼儿园保育员工作总结
2015/04/23 职场文书
干货!开幕词的写作方法
2019/04/02 职场文书
Apache Pulsar结合Hudi构建Lakehouse方案分析
2022/03/31 Servers