详解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 相关文章推荐
js全屏显示显示代码的三种方法
Nov 11 Javascript
jquery 判断滚动条到达了底部和顶端的方法
Apr 02 Javascript
jQuery淡入淡出元素让其效果更为生动
Sep 01 Javascript
简介JavaScript中POSITIVE_INFINITY值的使用
Jun 05 Javascript
JS实现的简易拖放效果示例
Dec 29 Javascript
JavaScript数据类型的存储方法详解
Aug 25 Javascript
当vue路由变化时,改变导航栏的样式方法
Aug 22 Javascript
vue中的适配px2rem示例代码
Nov 19 Javascript
vue下载excel的实现代码后台用post方法
May 10 Javascript
Layui实现主窗口和Iframe层参数传递
Nov 14 Javascript
JS实现网站吸顶条
Jan 08 Javascript
vue-video-player实现实时视频播放方式(监控设备-rtmp流)
Aug 10 Javascript
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
解析yahoo邮件用phpmailer发送的实例
2013/06/24 PHP
PHP使用数组实现矩阵数学运算的方法示例
2017/05/29 PHP
Laravel 添加多语言提示信息的方法
2019/09/29 PHP
javascript URL编码和解码使用说明
2010/04/12 Javascript
潜说js对象和数组
2011/05/25 Javascript
我的Node.js学习之路(二)NPM模块管理
2014/07/06 Javascript
jquery处理页面弹出层查询数据等待操作实例
2015/03/25 Javascript
javascript实现textarea中tab键的缩排处理方法
2015/06/26 Javascript
jquery实现表单验证简单实例演示
2015/11/23 Javascript
jQuery 1.9.1源码分析系列(十三)之位置大小操作
2015/12/02 Javascript
浅谈js for循环输出i为同一值的问题
2017/03/01 Javascript
vue小图标favicon不显示的解决方案
2017/09/19 Javascript
解决js ajax同步请求造成浏览器假死的问题
2018/01/18 Javascript
vue在index.html中引入静态文件不生效问题及解决方法
2019/04/29 Javascript
Django+Vue实现WebSocket连接的示例代码
2019/05/28 Javascript
Python中内建函数的简单用法说明
2016/05/05 Python
推荐10款最受Python开发者欢迎的Python IDE
2018/09/16 Python
使用Python和Prometheus跟踪天气的使用方法
2019/05/06 Python
Python简易版图书管理系统
2019/08/12 Python
Pycharm 字体大小调整设置的方法实现
2019/09/27 Python
基于Python的OCR实现示例
2020/04/03 Python
英国领先的在线旅游和休闲零售商:lastminute.com
2019/01/23 全球购物
双立人美国官方商店:ZWILLING集团餐具和炊具
2020/05/07 全球购物
大整数数相乘的问题
2012/07/22 面试题
大学生评语大全
2014/04/18 职场文书
优秀团员事迹材料1500字
2014/08/31 职场文书
企业务虚会发言材料
2014/10/20 职场文书
2014年保卫科工作总结
2014/12/05 职场文书
自荐信格式范文
2015/03/04 职场文书
2015年银行员工工作总结
2015/04/24 职场文书
2015年社区流动人口工作总结
2015/05/12 职场文书
校园广播稿范文
2015/08/19 职场文书
送给教师们,到底该如何写好教学反思?
2019/07/02 职场文书
SqlServer 垂直分表(减少程序改动)
2021/04/16 SQL Server
Python初识逻辑与if语句及用法大全
2021/08/07 Python
vue项目配置sass及引入外部scss文件
2022/04/14 Vue.js