前提
Es7 的装饰器借鉴的Python decorator语法糖的写法。这篇写了很久了,也忘了当初是看的哪一位大佬写的demo例子,今天翻出来了老笔记,就决定搬上来先吧,顺便复习下。
引申
如何对装饰器进行封装?(实现的方式)
Object.defineProperty(obj, prop, desc)
- obj: 目标对象
- prop: 属性名
- desc: 针对该属性的描述符
demo-1(作用在类的function上的装饰器)
下面用一个小demo来了解一波装饰器的用法:
首先定义一个装饰器函数readonly,作用为让数据可读
function readonly(tar, key, desc) {
desc.writable = false; // 数据只读
return desc;
}
定义一个类,装饰器搭配使用,让该类内的方法只读不可修改
class Dog {
@readonly //实际readonly接受tar参数就是bark.prototype
bark () {
return '666';
}
}
现在实例化一波,试试装饰器readonly作用了没
let dog = new Dog();
dog.bark = '777';
Cannot assign to read only property 'bark' of [object Object]
这边就挂了。
demo背后的实现原理
既然看到了class的语法,那就先说说class怎么用es5实现吧,引申一波:
通常来说,这样就行了
function Dog() {}
Dog.prototype.bark = function() {
return '666';
}
let dog = new Dog();
dog.bark(); // '666'
装逼点的写法
function Dog () {}
// 第二步修改defineProperty属性来添加一个bark的函数
let desc = {
value: function () {return '666';},
enumerable: false, // 可否枚举
configurable: true, // 可否修改/删除
writable: true, // 可否用数据运算符进行赋值修改
};
Object.defineProperty (Dog.prototype, 'bark', desc)
回归正题 针对@readonly 装饰器的es5实现
定义一个属性描述符 descriptor
let descriptor = {
value: function () { return '666' },
enumerable: false,
configurable: true,
writable: true
}
function readonly(tar, key, desc) {
desc.writable = false; // 数据只读
return desc;
}
let desc = readonly(Dog.prototype, 'bark', descriptor) || descriptor; // 二选一
Object.defineProperty(Dog.prototype, 'bark', desc);
demo-2(作用在class的装饰器)
定义类的装饰器函数
function doge(tar) {
tar.isDoge = true;
}
定义一个class,使用doge装饰器
@doge
class Dog {
}
Dog.isDoge // true
其实就是修改了defineProperty里面target属性,指向了Dog而不是Dog.prototype。
demo-3(装饰器的变量引入)
通过变量控制decorator的返回值
function doge (par) {
return function (tar) {
tar.isDoge = par;
}
}
@doge(false) // 控制返回值
class Dog {
}
Dog.isDoge // false
实际应用场景
react 与 redux 库的结合使用 正常使用
class ReactComponent extends React.Component {
}
export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);
使用装饰器
@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
注意事项
先来复习一下函数提升的问题
js创建函数的两种方式
function a() {} // 存在函数提升问题,整个代码块提升到最开始执行
var a = function() {} // 不存在该问题,与变量提升差不多
若一定要修饰函数,可以用HOC(高阶函数)去处理。
!!! 装饰器不能作用于函数本身,只能作用于类或类的方法上,存在函数提升的问题. 问题链接