详解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 模拟类搜索框自动完成搜索提示功能(改进)
May 24 Javascript
JavaScript中this详解
Sep 01 Javascript
js带点自动图片轮播幻灯片特效代码分享
Sep 07 Javascript
JavaScript 弹出子窗体并返回结果到父窗体的实现代码
May 28 Javascript
jsp 网站引入外部css或者js失效问题解决
Oct 31 Javascript
简单实现AngularJS轮播图效果
Apr 10 Javascript
JS实现根据密码长度显示安全条功能
Mar 08 Javascript
create-react-app 修改为多入口编译的方法
Aug 01 Javascript
JS与jQuery判断文本框还剩多少字符可以输入的方法
Sep 01 jQuery
详解如何搭建mpvue框架搭配vant组件库的小程序项目
May 16 Javascript
Layui tree 下拉菜单树的实例代码
Sep 21 Javascript
javascript实现简单搜索功能
Mar 26 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中的字符串函数
2006/11/24 PHP
php xml实例 留言本
2009/03/20 PHP
PHP 解决utf-8和gb2312编码转换问题
2010/03/18 PHP
php提交表单时判断 if($_POST[submit])与 if(isset($_POST[submit])) 的区别
2011/02/08 PHP
PHP中几种常见的超时处理全面总结
2012/09/11 PHP
php中限制ip段访问、禁止ip提交表单的代码分享
2014/08/22 PHP
php实现插入排序
2015/03/29 PHP
JS模拟面向对象全解(一、类型及传递)
2011/07/13 Javascript
Js四则运算函数代码
2012/07/21 Javascript
js中同步与异步处理的方法和区别总结
2013/12/25 Javascript
javascript下拉列表中显示树形菜单的实现方法
2015/11/17 Javascript
jQuery Validate表单验证插件 添加class属性形式的校验
2016/01/18 Javascript
jQuery中deferred对象使用方法详解
2016/07/14 Javascript
Vue.JS入门教程之列表渲染
2016/12/01 Javascript
基于js中style.width与offsetWidth的区别(详解)
2017/11/12 Javascript
JavaScript门道之标准库
2018/05/26 Javascript
小程序点赞收藏功能的实现代码示例
2018/09/07 Javascript
详解Webpack如何引入CDN链接来优化编译后的体积
2019/06/21 Javascript
小程序实现投票进度条
2019/11/20 Javascript
Node.js web 应用如何封装到Docker容器中
2020/09/01 Javascript
vue 动态添加的路由页面刷新时失效的原因及解决方案
2021/02/26 Vue.js
[56:58]VP vs Optic 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python 异常处理的实例详解
2017/09/11 Python
python实现在一个画布上画多个子图
2020/01/19 Python
python实现电子词典
2020/03/03 Python
python 识别登录验证码图片功能的实现代码(完整代码)
2020/07/03 Python
Python操作Word批量生成合同的实现示例
2020/08/28 Python
Timex手表官网:美国运动休闲手表品牌
2017/01/28 全球购物
台湾母婴用品购物网站:Infant婴之房
2018/06/15 全球购物
伦敦一家领先的精品零售商:IRIS Fashion
2019/05/24 全球购物
TALLY WEiJL法国网上商店:服装、时装及配饰
2019/08/31 全球购物
2015年大学生入党自荐书
2015/03/24 职场文书
消防安全主题班会
2015/08/12 职场文书
2019员工保密协议书(3篇)
2019/09/23 职场文书
使用goaccess分析nginx日志的详细方法
2021/07/09 Servers
Python中的tkinter库简单案例详解
2022/01/22 Python