发布于 2024 年 2 月 26 日,星期一
在业务代码中滥用装饰器可能带来的问题。装饰器虽然能增强代码的可读性和可维护性,但过度使用或在不恰当的场景下使用,会导致代码复杂度增加,降低可维护性,甚至引入潜在的错误。业务代码应注重简洁、高效和易于理解,过度追求技术炫技反而违背了这一原则。因此,开发者应谨慎使用装饰器,确保其在提升代码质量的同时,不增加不必要的复杂性和风险。
装饰器模式可在不改变现有对象解构的基础上,动态地为对象添加功能
。var plane = { fire: function () { console.log("普通子弹"); },};var missleDecorator = function () { console.log("发射导弹");};var atomDecorator = function () { console.log("发射原子弹");};var fire1 = plane.fire;plane.fire = function () { fire1(); missleDecorator();};var fire2 = plane.fire;plane.fire = function () { fire2(); atomDecorator();};plane.fire();/**
普通子弹
发射导弹
发射原子弹
*/
function a(){ console.log(1);}// 改写:function a(){ console.log(1); // 新功能 console.log(2);}
AOP 来装饰函数
。
Function.prototype.before = function (beforeFn) { var _self = this; return function () { beforeFn.apply(this, arguments); return _self.apply(this, arguments); };};Function.prototype.after = function (afterFn) { var _self = this; return function () { var ret = _self.apply(this, arguments); afterFn.apply(this, arguments); return ret; }}// before 和 after 函数都接收一个函数作为参数,这个函数也就是新添加的函数(里面也就是要添加的新功能逻辑)。// 而before 和 after 函数区别在于在是原函数之前执行还是之后执行。
Function.prototype.before = function (beforeFn) { var _self = this; return function () { beforeFn.apply(this, arguments); return _self.apply(this, arguments); };};Function.prototype.after = function (afterFn) { var _self = this; return function () { var ret = _self.apply(this, arguments); afterFn.apply(this, arguments); return ret; }}var o1 = function(){ console.log('1');}var o2 = function(){ console.log('2');}var o3 = function(){ console.log('3');}var desctor = o1.after(o2);desctor = desctor.after(o3);desctor(); // 1 2 3/**
var desctor = o1.after(o2);
desctor = desctor.after(o3);
desctor();
1
2
3
var desctor = o1.before(o2);
desctor = desctor.before(o3);
desctor();
3
2
1
var desctor = o1.after(o2);
desctor = desctor.before(o3);
desctor();
3
1
2
var desctor = o1.before(o2);
desctor = desctor.after(o3);
desctor();
2
1
3
*/
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>AOP日志上报</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://unpkg.com/vue@3.2.20/dist/vue.global.js"></script> </head> <body> <div id="app"> <button class="btn" @click="handler">Button</button> <p id="tt">{{message}}</p> </div> </body></html><script type="text/javascript">
// log report
const { reactive, ref, createApp } = Vue;
const app = createApp({
setup() {
const message = ref("未点击");
const count = ref(0);
Function.prototype.before = function (beforeFn) {
var _self = this;
return function () {
beforeFn.apply(this, arguments);
return _self.apply(this, arguments);
};
};
Function.prototype.after = function (afterFn) {
var _self = this;
return function () {
var ret = _self.apply(this, arguments);
afterFn.apply(this, arguments);
return ret;
};
};
function handler() {
message.value = `已点击${++count.value}`;
}
handler = handler.after(log);
function log() {
message.value = message.value + "-----> log reported";
console.log("log report");
}
return {
message,
handler,
};
},
});
app.mount("#app");
</script>
{ name: 'xxxx', password: 'xxxx',}
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>AOP动态参数</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://unpkg.com/vue@3.2.20/dist/vue.global.js"></script> </head> <body> <div id="app">{{message}}</div> </body></html><script type="text/javascript">
const { reactive, ref, createApp } = Vue;
const app = createApp({
setup() {
const message = ref("empty params");
Function.prototype.before = function (beforeFn) {
var _self = this;
return function () {
beforeFn.apply(this, arguments);
return _self.apply(this, arguments);
};
};
Function.prototype.after = function (afterFn) {
var _self = this;
return function () {
var ret = _self.apply(this, arguments);
afterFn.apply(this, arguments);
return ret;
};
};
function ajax(type, url, params){
message.value = `${type} ----> ${url} -----> ${JSON.stringify(params)}`;
}
function getToken(){
// do something
return 'token';
}
ajax = ajax.before(function(type, url, params){
params.token = getToken();
})
ajax('get', 'https://www.baidu.com/userinfo', {name: 'se', password: 'xsdsd'});
return {
message,
};
},
});
app.mount("#app");
</script>
<!DOCTYPE html><html lang="en"> <head> <meta charset="UTF-8" /> <title>AOP表单验证</title> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://unpkg.com/vue@3.2.20/dist/vue.global.js"></script> </head> <body> <div id="app"> <label> 姓名: <input
type="text"
v-model="data.name"
placeholder="请输入姓名"
/> </label> <label> 密码: <input
type="text"
v-model="data.pass"
placeholder="请输入密码"
/> </label> <p v-if="data.name || data.pass">{{data.name + '/' + data.pass}} ----after-----> {{data.message}}</p> <hr> <button @click="submitBtn">submit</button> </div> </body></html><script type="text/javascript">
const { reactive, ref, createApp, watchEffect } = Vue;
const app = createApp({
setup() {
const data = reactive({
name: "",
pass: "",
message: "",
});
Function.prototype.before = function (beforeFn) {
var _self = this;
return function () {
if (beforeFn.apply(this, arguments) === false) return;
return _self.apply(this, arguments);
};
};
function valid() {
if (!data.name || !data.pass) {
alert("用户名或密码不能为空");
return false;
}
}
function formSubmit() {
console.log("data ------>", data);
data.message = `${data.name} ------- ${data.pass}`;
}
formSubmit = formSubmit.before(valid);
function submitBtn() {
formSubmit();
}
return {
data,
submitBtn,
};
},
});
app.mount("#app");
</script>
曾探
大佬的《JavaScript 设计模式与开发实践》。文章仅做个人学习总结和知识汇总