你是怎么理解ES6中 Decorator 的?使用场景?
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
一、介绍
Decorator,即装饰器,从名字上很容易让我们联想到装饰者模式
简单来讲,装饰者模式就是一种在不改变原类和使用继承的情况下,动态地扩展对象功能的设计理论。
ES6中Decorator功能亦如此,其本质也不是什么高大上的结构,就是一个普通的函数,用于扩展类属性和类方法
这里定义一个士兵,这时候他什么装备都没有
class soldier{
}
定义一个得到 AK 装备的函数,即装饰器
function strong(target){
target.AK = true
}
使用该装饰器对士兵进行增强
@strong
class soldier{
}
这时候士兵就有武器了
soldier.AK // true
上述代码虽然简单,但也能够清晰看到了使用Decorator两大优点:
- 代码可读性变强了,装饰器命名相当于一个注释
- 在不改变原有代码情况下,对原来功能进行扩展
二、用法
Docorator修饰对象为下面两种:
- 类的装饰
- 类属性的装饰
类的装饰
当对类本身进行装饰的时候,能够接受一个参数,即类本身
将装饰器行为进行分解,大家能够有个更深入的了解
@decorator
class A {} // 等同于 class A {}
A = decorator(A) || A;
下面@testable就是一个装饰器,target就是传入的类,即MyTestableClass,实现了为类添加静态属性
@testable
class MyTestableClass {
// ...
} function testable(target) {
target.isTestable = true;
} MyTestableClass.isTestable // true
如果想要传递参数,可以在装饰器外层再封装一层函数
function testable(isTestable) {
return function(target) {
target.isTestable = isTestable;
}
}
@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true
@testable(false)
class MyClass {}
MyClass.isTestable // false
类属性的装饰
当对类属性进行装饰的时候,能够接受三个参数:
- 类的原型对象
- 需要装饰的属性名
- 装饰属性名的描述对象
首先定义一个readonly装饰器
function readonly(target, name, descriptor){
descriptor.writable = false; // 将可写属性设为false
return descriptor;
}
使用readonly装饰类的name方法
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}
相当于以下调用
readonly(Person.prototype, 'name', descriptor);
如果一个方法有多个装饰器,就像洋葱一样,先从外到内进入,再由内到外执行
function dec(id){
console.log('evaluated', id);
return (target, property, descriptor) =>console.log('executed', id);
}
class Example {
@dec(1)
@dec(2)
method(){}
}
// evaluated 1
// evaluated 2
// executed 2
// executed 1
外层装饰器@dec(1)先进入,但是内层装饰器@dec(2)先执行
注意
装饰器不能用于修饰函数,因为函数存在变量声明情况
var counter = 0;
var add = function () {
counter++;
};
@add
function foo() {
}
编译阶段,变成下面
var counter;
var add; @add
function foo() {
} counter = 0; add = function () {
counter++;
};
意图是执行后counter等于 1,但是实际上结果是counter等于 0
三、使用场景
基于Decorator强大的作用,我们能够完成各种场景的需求,下面简单列举几种:
使用react-redux的时候,如果写成下面这种形式,既不雅观也很麻烦
class MyReactComponent extends React.Component {}
export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);
通过装饰器就变得简洁多了
@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
将mixins,也可以写成装饰器,让使用更为简洁了
function mixins(...list) {
return function (target) {
Object.assign(target.prototype, ...list);
};
}
// 使用
const Foo = {
foo() { console.log('foo') }
};
@mixins(Foo)
class MyClass {}
let obj = new MyClass();
obj.foo() // "foo"
下面再讲讲core-decorators.js几个常见的装饰器
@antobind
autobind装饰器使得方法中的this对象,绑定原始对象
import { autobind } from 'core-decorators';
class Person {
@autobind
getPerson() {
return this;
}
}
let person = new Person();
let getPerson = person.getPerson;
getPerson() === person;
// true
@readonly
readonly装饰器使得属性或方法不可写
import { readonly } from 'core-decorators';
class Meal {
@readonly
entree = 'steak';
}
var dinner = new Meal();
dinner.entree = 'salmon';
// Cannot assign to read only property 'entree' of [object Object]
@deprecate
deprecate或deprecated装饰器在控制台显示一条警告,表示该方法将废除
import { deprecate } from 'core-decorators';
class Person {
@deprecate
facepalm() {}
@deprecate('功能废除了')
facepalmHard() {}
}
let person = new Person();
person.facepalm();
// DEPRECATION Person#facepalm: This function will be removed in future versions.
person.facepalmHard();
// DEPRECATION Person#facepalmHard: 功能废除了
参考文献
- https://es6.ruanyifeng.com/#docs/decorator
你是怎么理解ES6中 Decorator 的?使用场景?的更多相关文章
- 前端知识体系:JavaScript基础-原型和原型链-理解 es6 中class构造以及继承的底层实现原理
理解 es6 中class构造以及继承的底层实现原理 原文链接:https://blog.csdn.net/qq_34149805/article/details/86105123 1.ES6 cla ...
- 【JS】325- 深度理解ES6中的解构赋值
点击上方"前端自习课"关注,学习起来~ 对象和数组时 Javascript 中最常用的两种数据结构,由于 JSON 数据格式的普及,二者已经成为 Javascript 语言中特别重 ...
- 理解ES6中的Iterator
一.为什么使用Iterator 我们知道,在ES6中新增了很多的特性,包括Map,Set等新的数据结构,算上数组和对象已经有四种数据集合了,就像数组可以使用forEach,对象可以使用for...in ...
- 理解ES6中的Symbol
一.为什么ES6引入Symbol 有时候我们在项目开发的过程中可能会遇到这样的问题,我写了一个对象,而另外的同时则在这个对象里面添加了一个属性或是方法,倘若添加的这个属性或是方法是原本的对象中本来就有 ...
- 深入理解 ES6中的 Reflect
阅读目录 一:Reflect.get(target, name, receiver) 二:Reflect.set(target,name,value,receiver) 三:Reflect.apply ...
- 理解ES6中的Promise
一.Promise的作用 在ajax请求数据的过程中,我们可以异步拿到我们想要的数据,然后在回调中做相应的数据处理. 这样做看上去并没有什么麻烦,但是如果这个时候,我们还需要做另外一个ajax请求,这 ...
- 理解es6 中 arrow function的this
箭头函数相当于定义时候,普通函数.bind(this)箭头函数根本没有自己的this,导致内部的this就是定义时候的外层代码块中的this.外层代码块中的this,则取决于执行时候环境上下文cont ...
- 理解es6中的const与“不变”
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址不得改动. 效果 对于简单类型的数据(数值.字符串.布尔值),值就保存在变量指向的那个内存地址,因此等同于常量. 对于复合类型 ...
- 深入理解es6中的Promise
https://www.jianshu.com/p/9e4af5b77253 https://zhuanlan.zhihu.com/p/30797777 https://segmentfault.co ...
- 深入理解 JavaScript 异步系列(3)—— ES6 中的 Promise
第一部分,Promise 加入 ES6 标准 原文地址 http://www.cnblogs.com/wangfupeng1988/p/6515855.html 未经作者允许不得转载! 从 jquer ...
随机推荐
- JS Leetcode 263. 丑数 题解分析,来认识有趣的丑数吧
壹 ❀ 引 本题来自LeetCode263. 丑数,难度简单,题目描述如下: 给你一个整数 n ,请你判断 n 是否为 丑数 .如果是,返回 true :否则,返回 false . 丑数 就是只包含质 ...
- android架构组件Lifecycle
Lifecycle 组件指的是 android.arch.lifecycle 包下提供的各种类与接口,可以让开发者构建能感知其他组件(主要指Activity .Fragment)生命周期(lifecy ...
- 解决springboot整合freemarker页面跳转404
问题说明 spring boot 2.1.5集成freemarker时跳转报404! 集成过程说明 pom.xml <dependency> <groupId>org.free ...
- https://editor.csdn.net/md/?articleId=131348876
前言 前面搭建了基础环境,在使用统信UOS系统的相关行业也是不能上网的,但是可以传递压缩包,为了很好的方便相关从业人员工作,特将此种方式流程分享出来.(与国产银河麒麟不同) 本篇文章的重点就是离 ...
- collection.abc模块下的抽象基类UML类图说明
说明 Iterable.Container和Sized 每个容器都应该继承这三个抽象基类,或者实现兼容的协议.Iterable通过__iter__方法支持迭代, Container通过__contai ...
- python字典操作的大O效率
- Celery异步处理任务时遇到的错误ValueError: not enough values to unpack (expected 3, got 0)
开启celery异步,终端命令: celery -A celery_tasks.main worker -l info 如果上面运行后,发送短信码的时候没有报如下错误: ValueError: not ...
- C++ //常用拷贝和替换算法 //copy //replace 将指定区间范围内的旧元素修改为新元素 //replace_if(满足条件的元素,替换指定的元素) //swap 互换两个容器的元素
//常用拷贝和替换算法 //copy //replace 将指定区间范围内的旧元素修改为新元素 //replace_if(满足条件的元素,替换指定的元素) //swap 互换两个容器的元素 #incl ...
- 6、mysql的SQL优化
1. 大批量插入数据 1) 主键顺序插入 因为InnoDB类型的表是按照主键的顺序保存的,所以将导入的数据按照主键的顺序排列,可以有效的提高导入数据的效率.如果InnoDB表没有主键,那么系统会自动默 ...
- 5、zookeeper应用场景-配置中心原理
配置中心 使用 zookeeper的特性watcher监听器 工作中有这样的一个场景:数据库用户名和密码信息放在一个配置文件中,应用读取该配置文件,配置文件信息放入缓存 若数据库的用户名和密码改变时候 ...
