//ps:根据大佬的解释,现在提案修改,不推荐使用legacy这种模式了,新版模式待研究后再更新Orz
(ps:babel7以后插件名称全部有所改动)
yarn global add @babel/cli
yarn global add @babel/node
yarn add @babel/plugin-proposal-decorators
使用babel-node、babel-cli这样的名称只能安装到6版本的babel工具,7版本的工具全部改由@babel前缀
新建.babelrc文件:
{
"plugins":[
["@babel/plugin-proposal-pipeline-operator", { "proposal": "minimal" }],
["@babel/plugin-proposal-decorators",{"legacy":true}]]
}
新建index.js文件:
function testable(isTestable) {
return function(target) {
target.isTestable = isTestable;
}
}
@testable(true)
class MyTestableClass {}
console.log(MyTestableClass.isTestable)// true
@testable(false)
class MyClass {}
console.log(MyClass.isTestable)// false
然后执行:
babel-node index.js
即可看到对应的输出结果。
装饰器语法本身只是单纯的用一个函数去处理一个类,大多数时候都是对其prototype的修改,用es5也能实现对应的功能,但是使用装饰器能使代码更加简洁,结构更加清晰。
虽然在js中,class和function不存在本质上的区别,只是一个语法糖的存在,但是由于函数的作用域提升的问题,如果函数中有自由变量的使用,就会出现不可预期的一些bug。
例如如下代码:(案例来自阮一峰es6教程)
var counter = 0;
var add = function () {
counter++;
};
@add
function foo() {
}
在实际编译后,会变成如下:
@add
function foo() {
}
var counter;
var add;
counter = 0;
add = function () {
counter++;
};
从而导致程序出粗。
function AOP(options) {
const {beforeFunc,afterFunc}=Object.assign({
beforeFunc:()=>{},
afterFunc:()=>{}
},options)
return function(target, key, descriptor) {
const oldTarget = descriptor.value
descriptor.value=function(){
beforeFunc.apply(this,arguments)
const value=oldTarget.apply(this,arguments)
afterFunc.apply(this.arguments)
return value
}
return descriptor
}
}
function logBefore(){
console.log("before")
}
function logAfter(){
console.log("after")
}
class MyClass {
@AOP({
beforeFunc:logBefore,
afterFunc:logAfter
})
func(){
console.log("run")
}
}
const obj=new MyClass()
obj.func()
这样每次就简单清晰的注入了before和after两个函数,在这两个函数中可以做数据预处理、数据状态监测等等一系列的功能,包括GA数据的监测也可以这样放入。这样和JAVA的AOP思路就十分的接近了。