详解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 相关文章推荐
通过JAVASCRIPT读取ASP设定的COOKIE
Feb 15 Javascript
jQuery使用手册之二 DOM操作
Mar 24 Javascript
filemanage功能中用到的common.js
Apr 08 Javascript
js 日期转换成中文格式的函数
Jul 07 Javascript
innerHTML与jquery里的html()区别介绍
Oct 12 Javascript
js 获取和设置css3 属性值的实现方法
May 06 Javascript
javascript写的异步加载js文件函数(支持数组传参)
Jun 07 Javascript
JS取得绝对路径的实现代码
Jan 16 Javascript
JavaScript中的toUTCString()方法使用详解
Jun 12 Javascript
详解如何在vue项目中使用layui框架及采坑
May 05 Javascript
jquery实现上传文件进度条
Mar 26 jQuery
实例讲解React 组件生命周期
Jul 08 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
php echo, print, print_r, sprintf, var_dump, var_expor的使用区别
2013/06/20 PHP
php中preg_replace正则替换用法分析【一次替换多个值】
2017/01/17 PHP
Laravel 实现Eloquent模型分组查询并返回每个分组的数量 groupBy()
2019/10/23 PHP
php反序列化长度变化尾部字符串逃逸(0CTF-2016-piapiapia)
2020/02/15 PHP
JavaScript Undefined,Null类型和NaN值区别
2008/10/22 Javascript
JS获取下拉列表所选中的TEXT和Value的实现代码
2014/01/11 Javascript
jquery toolbar与网页浮动工具条具体实现代码
2014/01/12 Javascript
基于javascript实现的搜索时自动提示功能
2014/12/26 Javascript
javascript实现自动填写表单实例简析
2015/12/02 Javascript
javascript中arguments,callee,caller详解
2016/03/16 Javascript
Nodejs下用submit提交表单提示cannot post错误的解决方法
2016/11/21 NodeJs
AngularJs表单验证实例代码解析
2016/11/29 Javascript
详解vue 配合vue-resource调用接口获取数据
2017/06/22 Javascript
解决Linux无法正常安装与卸载Node.js的方法
2018/01/19 Javascript
vue 实现复制内容到粘贴板clipboard的方法
2018/03/17 Javascript
对Layer弹窗使用及返回数据接收的实例详解
2019/09/26 Javascript
python实现监控linux性能及进程消耗性能的方法
2014/07/25 Python
python命令行参数解析OptionParser类用法实例
2014/10/09 Python
python实现杨辉三角思路
2017/07/14 Python
浅谈Python中的zip()与*zip()函数详解
2018/02/24 Python
使用Python和xlwt向Excel文件中写入中文的实例
2018/04/21 Python
python脚本监控Tomcat服务器的方法
2018/07/06 Python
在Python中调用Ping命令,批量IP的方法
2019/01/26 Python
对Python3 解析html的几种操作方式小结
2019/02/16 Python
Python数据类型之Tuple元组实例详解
2019/05/08 Python
python实现合并多个list及合并多个django QuerySet的方法示例
2019/06/11 Python
Python 中的参数传递、返回值、浅拷贝、深拷贝
2019/06/25 Python
python遍历文件目录、批量处理同类文件
2019/08/31 Python
python连接mysql数据库并读取数据的实现
2020/09/25 Python
CK巴西官方网站:Calvin Klein巴西
2019/07/19 全球购物
英国领先的在线高尔夫商店:Scottsdale Golf
2019/08/26 全球购物
Hotels.com韩国:海外国内旅行所需的酒店和住宿预订网站
2020/05/08 全球购物
沈阳故宫导游词
2015/01/31 职场文书
全陪导游词开场白
2015/05/29 职场文书
MySQL Innodb索引机制详细介绍
2021/11/23 MySQL
英国数字版游戏销量周榜公布 《小缇娜的奇幻之地》登顶
2022/04/03 其他游戏