持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情
前情提要
装饰器模式又称修饰器模式,目前babel已经完全支持了对其的转码,所以我们可以在项目里开始使用了。并且在Typescript中就有大量的使用装饰器模式。
什么是装饰器模式?
- 用一句话解释就是允许我们给一个对象拓展新的功能,但是又不改变原对象,属于非侵入式的拓展。
- 跟java的注解形似,但是功能还是有较大差别的。
- 打一个不恰当的比喻,就像我们玩的王者荣耀,每个英雄都是独立的对象,每个装备就是一个个装饰器,英雄购买了装备就只是在身上进行装备,而对英雄本身没有改变,但是其攻击等属性却得到了提升。
- 装饰器可以为类进行拓展,可以为方法进行拓展,也可以给属性进行拓展。
- 属于ES7中的新特性
基于装饰器模式实现对类的拓展
- 简易的代码实现
class Hero { @addAttrs speak() { console.log('我是一个英雄') } } function addAttrs(target, key, descripteor) { console.log(target, key, descripter); console.log('我为这个英雄增加100点暴击伤害'); } const newHero = new Hero(); newHero.speak(); - 如果把这段代码直接复制到浏览器或者Nodejs环境执行的话你会发现报错了,无法识别@这个符号。因为装饰器是ES7的新特性,所以现在的浏览器或者Nodejs环境还没有适配。
- 此时我们需要使用babel这个神器帮我们将ES7的语法转换成ES5的代码。
使用babel将装饰器模式进行转译
- 将咱们写的代码所在的js文件移动到一个新的文件夹中
- 执行
npm init命令进行初始化,让填的信息填好。此时会新增一个package.json文件 - 创建一个.babelrc文件
- 编辑.babelrc文件:
{
"presets": ["env"],
"plugins": ["transform-decorators-legacy"]
}
- 打开终端或者cmd命令窗口,cd到该目录,然后执行命令:
npm i -S babel-cli babel-preset-env babel-plugin-transform-decorators-legacy - 在package.json文件中会发现这几个插件的信息都罗列在里面了。此时我们需要在script中新增一个启动命令:
“build”: "babel ./index.js -o build/index.js"- 此处的index.js是我创建的js文件名字,如果你起了别的名字,那么此处就需要做更改。
- 此时需要在文件夹中新增build文件夹,用来存放编译后的文件。
- 然后我们执行:
npm run build,之后我们就可以在build文件夹中看到编译后的js文件了。 - 此时我们就可以运行这个编译后的文件了。
上面简易代码运行的分析
-
这是代码运行后的结果
-
从浏览器中我们发现在执行speak方法之前先执行的我们给speak拓展的方法。
-
而作为装饰器方法接收了三个参数:
- target:我们拓展的方法所在的类实例
- key: 我们拓展的方法的方法名
- descriptor: 我们拓展的方法的属性
上面实现的是没有传参的情况,那么如果有参数怎么办呢?
class Hero {
@addAttrs('攻击加1000')
speak(attrs) {
attrs.forEach((item) => {
console.log(item)
})
}
}
function addAttrs(attr) {
return function (target, key, descriptor) {
const oldValue = descriptor.value; // 之前的speak方法
descriptor.value = function(...arg) { // 此处重写上面方法,然后在重写的方法里面进行调用之前的方法
arg[0].push(attr);
return oldValue.call(target, ...arg)
}
}
}
const newHero = new Hero();
newHero.speak(['法术强度加1000', '物理穿透加100000']);
- 使用上面转译方法进行转译之后的运行结果: