详解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高级程序设计阅读笔记(六) ECMAScript中的运算符(二)
Feb 27 Javascript
Bootstrap每天必学之下拉菜单
Nov 25 Javascript
全面了解JavaScirpt 的垃圾(garbage collection)回收机制
Jul 11 Javascript
JavaScript学习笔记整理_关于表达式和语句
Sep 19 Javascript
微信小程序 登录的简单实现
Apr 19 Javascript
AngularJS实现根据不同条件显示不同控件
Apr 20 Javascript
jQuery滚动插件scrollable.js用法分析
May 25 jQuery
vue proxyTable 接口跨域请求调试的示例
Sep 12 Javascript
vue params、query传参使用详解
Sep 12 Javascript
JS获取url参数,JS发送json格式的POST请求方法
Mar 29 Javascript
vue router 跳转时打开新页面的示例方法
Jul 28 Javascript
js中Function引用类型常见有用的方法和属性详解
Dec 11 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引用效率问题分析
2012/03/23 PHP
php获取网页标题和内容函数(不包含html标签)
2014/02/03 PHP
在Ubuntu 14.04上部署 PHP 环境及 WordPress
2014/09/02 PHP
PHP实现创建一个RPC服务操作示例
2020/02/23 PHP
php设计模式之中介者模式分析【星际争霸游戏案例】
2020/03/23 PHP
myEvent.js javascript跨浏览器事件框架
2011/10/24 Javascript
js获得网页背景色和字体色的方法
2014/03/21 Javascript
jquery 为a标签绑定click事件示例代码
2014/06/23 Javascript
JavaScript验证18位身份证号码最后一位正确性的实现代码
2014/08/07 Javascript
JavaScript中数据结构与算法(三):链表
2015/06/19 Javascript
js针对ip地址、子网掩码、网关的逻辑性判断
2016/01/06 Javascript
限时抢购-倒计时的完整实例(分享)
2017/09/17 Javascript
AngularJS实现的输入框字数限制提醒功能示例
2017/10/26 Javascript
纯JS实现的读取excel文件内容功能示例【支持所有浏览器】
2018/06/23 Javascript
JS获取今天是本月第几周、本月共几周、本月有多少天、是今年的第几周、是今年的第几天的示例代码
2018/12/05 Javascript
node获取客户端ip功能简单示例
2019/08/24 Javascript
jquery选择器和属性对象的操作实例分析
2020/01/10 jQuery
Nodejs在局域网配置https访问的实现方法
2020/10/17 NodeJs
vue实现顶部菜单栏
2020/11/08 Javascript
[00:35]可解锁地面特效
2018/12/20 DOTA
[42:06]2019国际邀请赛全明星赛 8.23
2019/09/05 DOTA
python实现查找两个字符串中相同字符并输出的方法
2015/07/11 Python
Python的包管理器pip更换软件源的方法详解
2016/06/20 Python
Django异步任务之Celery的基本使用
2019/03/23 Python
python 读写excel文件操作示例【附源码下载】
2019/06/19 Python
java中的控制结构(if,循环)详解
2019/06/26 Python
python使用writerows写csv文件产生多余空行的处理方法
2019/08/01 Python
Python绘制热力图示例
2019/09/27 Python
python绘制BA无标度网络示例代码
2019/11/21 Python
节日快乐! Python画一棵圣诞树送给你
2019/12/24 Python
Python连接Oracle之环境配置、实例代码及报错解决方法详解
2020/02/11 Python
一个非常简单好用的Python图形界面库(PysimpleGUI)
2020/12/28 Python
欧舒丹澳洲版:L’OCCITANE
2017/07/17 全球购物
数据库方面面试题
2012/04/22 面试题
党的群众路线教育实践活动专题组织生活会发言材料
2014/10/17 职场文书
大学生各类奖学金申请书
2019/06/24 职场文书