详解ES7 Decorator 入门解析


Posted in Javascript onFebruary 18, 2019

Decorator 提供了一种独特的抽象逻辑,可在原有代码基础上,零侵入添加新功能特性。商业代码总是多种交织并存的,在日常开发中,除了实现业务功能之外,我们还需要考虑诸如:异常处理、性能分析、日志等额外的需求。未经设计的的开发方法会倾向于将各种需求耦合组成一个功能模块,比如:

class Math{
 static add(num1,num2){
  try{
   console.time('some label');
   log('log for something');
   const result= num1+num2;
   console.timeEnd('some label');
   return result;
  }catch(e){
   error('something had broken');
  }
 }
}

上述简单的两数相加功能,在添加各类需求之后,已经变的面目全非。Decorator 语法通过描述,可将功能特性叠加到原有功能中:

class Math{
 @log
 @error
 @time
 static add(num1,num2){
  return num1+num2;
 }
}

Decorator 是什么

Decorator 就是一个的包裹函数,运行时在编译阶段调用该函数,修改目标对象的行为、属性。我们先来看一个简单实例:

const log = (target,prop)=>console.log(`Wrap function: '${prop}'`);

const tec={
 @log
 say(){
  console.log('hello world')
 }
}

// => Wrap function 'say'

Decorator 函数签名如下:

// @param  target 作用对象
// @param  prop  作用的属性名
// @param  descriptor 属性描述符
// @return descriptor 属性描述符
function decorator(target,prop,descriptor){}

参数详解:

  • target : 作用的对象,有如下情况:
    • 作用于 class 时,target 为该 class 函数
    • 作用于 class 中的函数、属性 时,target 为该 class 的 prototype 对象
    • 作用于 对象字面量中的函数、属性 时,target 为该对象
  • prop : 描述的属性名,若decorator作用于class时,该参数为空
  • descriptor : 属性原本的描述符,该描述符可通过Object.getOwnPropertyDescriptor() 获取,若decorator作用于class时,该参数为空
  • decorator 函数支持返回描述符或 undefined,当返回值为描述符时,运行时会调用Object.defineProperty()修改原有属性。

Decorator 的ES5实现

理解 Decorator 机制,最佳方式是使用ES5实现该过程。

class装饰器机制比较简单,仅做一层包装,伪代码:

// 调用实例
@log 
class Person{}
// 实现代码
const Person = log(Person);

属性装饰器机制则比较复杂,babel 就此提供了一个参考范例:

// decorator 处理
function _applyDecoratedDescriptor(target, property, decorators, descriptor, context) {
 var desc = {};
 Object['ke' + 'ys'](descriptor).forEach(function (key) {
  desc[key] = descriptor[key];
 });
 desc.enumerable = !!desc.enumerable;
 desc.configurable = !!desc.configurable;

 if ('value' in desc || desc.initializer) {
  desc.writable = true;
 }

 desc = decorators.slice().reverse().reduce(function (desc, decorator) {
  return decorator(target, property, desc) || desc;
 }, desc);

 if (context && desc.initializer !== void 0) {
  desc.value = desc.initializer ? desc.initializer.call(context) : void 0;
  desc.initializer = undefined;
 }

 if (desc.initializer === void 0) {
  Object['define' + 'Property'](target, property, desc);
  desc = null;
 }

 return desc;
}

// 调用实例
class Person{
 @log
 say(){}
}

// 实现代码
_applyDecoratedDescriptor(
 Person.prototype, 
 'say', 
 [log],
 Object.getOwnPropertyDescriptor(Person.prototype, 'say'),
 Person.prototype)
)

用例

Decorator 主要应用于如下几类对象:

  1. class
  2. class 中,除构造函数外的方法
  3. class 中的属性
  4. 对象字面量中的函数
  5. 对象字面量中的属性
// 类
@log
class Person{
 // 函数
 @log
 say(){}
 
 // 属性
 @log
 name = 'tec';
}

// 同样适用于对象字面量的方法、属性
const tec = {
 @log
 name:'tec',
 
 @log
 walk(){}
};

Decorator 实践

在JS中,Decorator 是一个新概念,对于多数没有接触过诸如python、C#的开发者而言,很难理解实际应用场景。幸运的是github已经有人封装了常用Decorator。笔者分析该库,总结如下几种定义模式:

通过 descriptor 的 value 值修改:

function decorate(target, key, descriptor) {
 const fn = descriptor.value;

 return {
  ...descriptor,
  value() {
   return fn.apply(this, arguments);
  }
 }
}

通过 descriptor 的 get、set 函数修改:

function decorate(target, key, descriptor) {
 let value = descriptor.value;

 return {
  ...descriptor,
  get() {
   return value;
  }
  set(v) {
   value=v;
  }
 }
}

通过 descriptor 的 writable、enumerable 等属性修改:

function readonly(target, key, descriptor) {
 return {
  ...descriptor,
  writable:false
 }
}

针对 class ,返回包裹函数

function log(target){
 let initTimes=0;
 return (...arg)=>{
  console.log(++initTimes);
  target.call(this,...arg);
 };
}

在实际开发中,还需要注意以下事项:

  • Decorator 的目标是在原有功能基础上,添加功能,切忌覆盖原有功能
  • Decorator 不是管道模式,decorator之间不存在交互,所以必须注意保持decorator独立性、透明性
  • Decorator 更适用于非业务功能需求
  • 确定 decorator 的用途后,切记执行判断参数类型
  • decorator 针对每个装饰目标,仅执行一次

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
DB.ASP 用Javascript写ASP很灵活很好用很easy
Jul 31 Javascript
javascript使用isNaN()函数判断变量是否为数字
Sep 21 Javascript
jquery在项目中做复选框时遇到的一些问题笔记
Nov 17 Javascript
js中数组排序sort方法的原理分析
Nov 20 Javascript
JQuery的ON()方法支持的所有事件罗列
Feb 28 Javascript
简单介绍JavaScript的变量和数据类型
Jun 03 Javascript
JavaScript实现的MD5算法完整实例
Feb 02 Javascript
vue.js element-ui validate中代码不执行问题解决方法
Dec 18 Javascript
详解vue静态资源打包中的坑与解决方案
Feb 05 Javascript
js中Object.defineProperty()方法的不详解
Jul 09 Javascript
JS获取当前时间的实例代码(昨天、今天、明天)
Nov 13 Javascript
微信小程序新手教程之启动页的重要性
Mar 03 Javascript
jQuery插件实现非常实用的tab栏切换功能【案例】
Feb 18 #jQuery
详解关于微信setData回调函数中的坑
Feb 18 #Javascript
jQuery实现的五星点评功能【案例】
Feb 18 #jQuery
JS中min函数实例讲解
Feb 18 #Javascript
jQuery实现的隔行变色功能【案例】
Feb 18 #jQuery
小程序实现列表多个批量倒计时
Jan 29 #Javascript
记一次vue-webpack项目优化实践详解
Feb 17 #Javascript
You might like
全国FM电台频率大全 - 1 北京市
2020/03/11 无线电
ThinkPHP调用百度翻译类实现在线翻译
2014/06/26 PHP
PHP计算一年多少个星期和每周的开始和结束日期
2014/07/01 PHP
PHP+Ajax检测用户名或邮件注册时是否已经存在实例教程
2014/08/23 PHP
Laravel 4.2 中队列服务(queue)使用感受
2014/10/30 PHP
PHP实现的策略模式简单示例
2017/08/25 PHP
收集的网上用的ajax之chat.js文件
2007/04/08 Javascript
EXT中xtype的含义分析
2010/01/07 Javascript
jQuery AJAX 调用WebService实现代码
2010/03/24 Javascript
Jquery下attr和removeAttr的使用方法
2010/12/28 Javascript
JQuery扩展插件Validate 1 基本使用方法并打包下载
2011/09/05 Javascript
你必须知道的Javascript知识点之"单线程事件驱动"的使用
2013/04/23 Javascript
js为空或不是对象问题的快速解决方法
2013/12/11 Javascript
Adapter适配器模式在JavaScript设计模式编程中的运用分析
2016/05/18 Javascript
JS实现的适合做faq或menu滑动效果示例
2016/11/17 Javascript
使用JavaScript根据图片获取条形码的方法
2017/07/04 Javascript
详解使用React进行组件库开发
2018/02/06 Javascript
JS闭包经典实例详解
2018/12/20 Javascript
微信小程序用户授权,以及判断登录是否过期的方法
2019/05/10 Javascript
微信小程序从注册账号到上架(图文详解)
2019/07/17 Javascript
详解Vue3中对VDOM的改进
2020/04/23 Javascript
[00:35]2016完美“圣”典风云人物:冷冷宣传片
2016/12/08 DOTA
[47:03]完美世界DOTA2联赛PWL S3 access vs LBZS 第一场 12.20
2020/12/23 DOTA
python编写爬虫小程序
2015/05/14 Python
Python开发之快速搭建自动回复微信公众号功能
2016/04/22 Python
Django在admin后台集成TinyMCE富文本编辑器的例子
2019/08/09 Python
Python实现企业微信机器人每天定时发消息实例
2020/02/25 Python
使用python实现时间序列白噪声检验方式
2020/06/03 Python
Python tkinter之Bind(绑定事件)的使用示例
2021/02/05 Python
python压包的概念及实例详解
2021/02/17 Python
css3 给背景设置渐变色的方法
2019/09/12 HTML / CSS
X/HTML5 和 XHTML2
2008/10/17 HTML / CSS
德国鞋子网上商店:Omoda.de
2017/03/31 全球购物
澳大利亚家用电器在线商店:Billy Guyatts
2020/05/05 全球购物
美容院合作经营协议书
2014/10/10 职场文书
Win11 引入 Windows 365 云操作系统,适应疫情期间混合办公模式:启动时直接登录、模
2022/04/06 数码科技