详解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 相关文章推荐
一个简单的jQuery插件制作 学习过程及实例
Apr 25 Javascript
JQuery魔力之$("tagName")与selector
Mar 05 Javascript
jquery控制select的text/value值为选中状态
Jun 03 Javascript
jquery实现增加删除行的方法
Feb 03 Javascript
JavaScript模拟可展开、拖动与关闭的聊天窗口实例
May 12 Javascript
高性能JavaScript DOM编程(1)
Aug 11 Javascript
基于jQuery实现美观且实用的倒计时实例代码
Dec 30 Javascript
javascript嵌套函数和在函数内调用外部函数的区别分析
Jan 31 Javascript
VC调用javascript的几种方法(推荐)
Aug 09 Javascript
jQuery、zepto、js常用小技巧
Feb 12 Javascript
微信小程序自定义多列选择器使用详解
Jun 21 Javascript
Vue自定义组件双向绑定实现原理及方法详解
Sep 03 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初学者头疼十四条问题大总结
2008/11/12 PHP
最新的php 文件上传模型,支持多文件上传
2009/08/13 PHP
PHP 网络开发详解之远程文件包含漏洞
2010/04/25 PHP
PHP备份数据库生成SQL文件并下载的函数代码
2012/02/05 PHP
php读取txt文件组成SQL并插入数据库的代码(原创自Zjmainstay)
2012/07/31 PHP
php 删除目录下N分钟前创建的所有文件的实现代码
2013/08/10 PHP
PHP SplObjectStorage使用实例
2015/05/12 PHP
PHP中addslashes()和stripslashes()实现字符串转义和还原用法实例
2016/01/07 PHP
使用JavaScript创建新样式表和新样式规则
2016/06/14 PHP
php获取开始与结束日期之间所有日期的方法
2016/11/29 PHP
thinkPHP5框架路由常用知识点汇总
2019/09/15 PHP
jBox 2.3基于jquery的最新多功能对话框插件 常见使用问题解答
2011/11/10 Javascript
Javascript实现重力弹跳拖拽运动效果示例
2013/06/28 Javascript
非常好用的JsonToString 方法 简单实例
2013/07/18 Javascript
jquery默认校验规则整理
2014/03/24 Javascript
JavaScript中解析JSON数据的三种方法
2015/07/03 Javascript
jQuery选择器用法实例详解
2015/12/17 Javascript
JavaScript自学笔记(必看篇)
2016/06/23 Javascript
使用JavaScriptCore实现OC和JS交互详解
2017/03/28 Javascript
Nodejs读取文件时相对路径的正确写法(使用fs模块)
2017/04/27 NodeJs
vue2.0模拟锚点的实例
2018/03/14 Javascript
Node.JS用纯JavaScript生成图片或滑块式验证码功能
2019/09/12 Javascript
JavaScript实现HSL拾色器
2020/05/21 Javascript
uniapp 仿微信的右边下拉选择弹出框的实现代码
2020/07/12 Javascript
Vue+scss白天和夜间模式切换功能的实现方法
2021/01/05 Vue.js
Python多线程经典问题之乘客做公交车算法实例
2017/03/22 Python
Python针对给定列表中元素进行翻转操作的方法分析
2018/04/27 Python
Python 自动登录淘宝并保存登录信息的方法
2019/09/04 Python
python如何使用jt400.jar包代码实例
2019/12/20 Python
Python+unittest+requests 接口自动化测试框架搭建教程
2020/10/09 Python
html5指南-4.使用Geolocation实现定位功能
2013/01/07 HTML / CSS
是否可以从一个static方法内部发出对非static方法的调用?
2014/08/18 面试题
忠诚教育心得体会
2014/09/03 职场文书
2014年群众路线教育实践活动整改措施
2014/09/24 职场文书
部门2015年度工作总结
2015/04/29 职场文书
tensorflow学习笔记之tfrecord文件的生成与读取
2021/03/31 Python