南阳住房和城乡建设管理局网站wordpress门户主体
web/
2025/10/7 22:07:39/
文章来源:
南阳住房和城乡建设管理局网站,wordpress门户主体,网站建设.国风网络,怎么开发微信公众号呢js设计模式
设计模式#xff08;Design pattern#xff09;代表了最佳的实践#xff0c;通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误…js设计模式
设计模式Design pattern代表了最佳的实践通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。 而虽然js前端使用设计模式不像后端那么频繁但是依然是一名程序员必备的本领本文通过使用实例方便大家理解记忆设计模式可用于面试前速记。 一. 设计模式介绍 在js设计模式中核心封装变化。 将变与不变分离确保变化灵活不变稳定。
构造器原型模式 使用设计模式前 var employee1 {name:zs,age:18}var employee2 {name:ls,age:19}在构造对象时如果数据量变多对象的代码会变得冗余臃肿 使用设计模式后
function Employee(name,age){this.name name;this.age age;this.say function(){console.log(this.name-,this.age)}
}
new Employee(zs,18)
new Employee(ls,19)工厂模式 由一个工厂对象决定创建某一种产品的对象类的实例。主要用来创建同一类对象。 只需要传入参数就能返回具体的实例。
function UserFactory(role){function User(role,pages){this.role role;this.pages pages;}switch(role){case superadmin:return new User(superadmin,[home,user-manage,right-manage,news-manage])break;case admin:return new User(admin,[home,user-manage,news-manage])break;case editor:return new User(editor,[home,news-manage])break;default:throw new Error(参数错误)}
}抽象工厂模式 相比于工厂模式抽象工厂模式会抽离出一个不变的公共父类。其子类就是各种的不同类。再通过函数判断返回这写不同的类。它并不会直接生成可用实例。而是返回不同的类让开发者得到想要的类后自行实例化。
class User {constructor(name) {this.name name}welcome() {console.log(欢迎回来, this.name)}dataShow() {throw new Error(抽象方法不允许直接调用)}
}class Editor extends User {constructor(name) {super(name)this.role editorthis.pages [home, news-manage]}dataShow() {console.log(editor的可视化逻辑)}
}class Admin extends User {constructor(name) {super(name)this.role adminthis.pages [home, user-manage, news-manage]}dataShow() {console.log(admin的可视化逻辑)}AddUser() {console.log(adduser方法)}
}class SuperAdmin extends User {constructor(name) {super(name)this.role superadminthis.pages [home, user-manage, right-manage, news-manage]}dataShow() {console.log(superadmin的可视化逻辑)}AddUser() {console.log(adduser方法)}AddRight() {console.log(addright方法)}
}function getAbstractUserFactory(role) {switch (role) {case superadmin:return SuperAdmin;break;case admin:return Admin;break;case editor:return Editor;break;default:throw new Error(参数错误)}
}建造者模式 假如你是一个工厂的设计师同过前面的工厂或抽象工厂模式已经获得了一个个独立的零件。接下来要拼接在一起成一个新的大零件。你现在已经不需要关心小零件构造只需要关心大零件的组成结构与顺序。这就是建造者模式
class Navbar {//没一个类的细节都不同init() {console.log(navbar-init)}getData() {return new Promise((resolve) {setTimeout(() {resolve()console.log(navbar-getData)}, 1000)})}render() {console.log(navbar-render)}
}
class List {init() {console.log(List-init)}getData() {return new Promise((resolve) {setTimeout(() {resolve()console.log(List-getData)}, 1000)})}render() {console.log(List-render)}
}class Operator {async startBuild(builder) {//设计师只关心这个函数中代码的运行逻辑await builder.init()await builder.getData()await builder.render()}
}const op new Operator();
const navbar new Navbar();
const list new List();
op.startBuild(navbar);
op.startBuild(list); 单例模式 作为设计师的你有一个工具包工具包里有且只有一个趁手的工具。你每次都只会使用这个工具。然而一开始你并没有工具包你可以买一个并一直使用这一个 为防止全局污染可以使用闭包来封闭一个变量这就是单例模式的原理。 保证一个类仅有一个实例并提供一个访问它的全局访问点。 主要解决一个全局使用的类频繁地创建和销毁占用内存。 const Modal (function () {let modal nullreturn function () {//返回一个类但是由于modal变量访问了外层作用域所以缓存不会立即释放if (!modal) {modal document.createElement(div)modal.innerHTML 登录对话框modal.className kerwin-modalmodal.style.display nonedocument.body.appendChild(modal)}return modal}})()document.querySelector(#open).addEventListener(click, function () {const modal new Modal()modal.style.display block})document.querySelector(#close).addEventListener(click, function () {const modal new Modal()modal.style.display none})装饰器模式 假设工厂中生产的是一台电视在设计电视时总会有开机广告这是固定好的但又跟电视本身的内容无关联那么开机广告就是有前置装饰器设置的。 对已有功能进行拓展这样不会更改原有代码对其他的业务产生影响这方便我们在较少的改动下对软件进行拓展。 Function.prototype.before function (beforeFn) {var _this this;return function () {beforeFn.apply(this, arguments);return _this.apply(this, arguments);};};
Function.prototype.after function (afterFn) {var _this this;//函数体本省return function () {//返回一个新的函数var ret _this.apply(this, arguments);afterFn.apply(this, arguments);return ret;};
};function test() {console.log(11111)
}
var test1 test.before(() {console.log(00000)
}).after((){console.log(22222)
})test1()适配模式 工厂中的水管并不是大小一样的这时候使用一个首尾大小不一样的适配器工具可以解决此问题 可以理解为类中的函数柯里化 将一个类的接口转换成客户希望的另一个接口。适配器模式让那些接口不兼容的类可以一起工作比如在原本的函数外再嵌一个函数这样调用函数名变了但我们使用适配器改变了原有的函数名变为了调用的函数名这在以下项目中更改接口api很有用 //按照官网代码复制
class TencentMap {show() {console.log(开始渲染腾讯地图);}
}
//按照官网代码复制
class BaiduMap {display() {console.log(开始渲染百度地图);}
}class BaiduMapAdapter extends BaiduMap {constructor() {super();}render() {this.display();}
}
class TencentMapAdapter extends TencentMap {constructor() {super();}render() {this.show();}
}
// 外部调用者
function renderMap(map) {map.render(); // 统一接口调用
}
renderMap(new TencentMapAdapter());
renderMap(new BaiduMapAdapter());策略模式 假如你作为设计师处理一件很复杂的事情你可以选择一个人扛也可以选择采用身边助理的意见。策略模式就是如此。将if else分开放到对象中去。这样想要加逻辑时就不必关注if else的先后顺序。 var list [{title: 男人看了沉默,type: 1},{title: 震惊,type: 2},{title: kerwin来了,type: 3},{title: tiechui离开了,type: 2}]let obj {1: {content: 审核中,className: yellowitem},2: {content: 已通过,className: greenitem},3: {content: 被驳回,className: reditem}}mylist.innerHTML list.map(item lidiv${item.title}/div div class${obj[item.type].className}${obj[item.type].content}/div /li).join()代理模式 代理模式Proxy为其他对象提供一种代理以控制对这个对象的访问。 代理模式使得代理对象控制具体对象的引用。代理几乎可以是任何对象文件资源内存中的对象或者是一些难以复制的东西。 准确来说就好似Proxy进行代理通过其代理功能可以过滤掉一些禁用。缺点是必须访问代理后的对象不会影响原有对象。vue3响应式底层原理
let obj {}
let proxy new Proxy(obj,{get(target,key){console.log(get,target[key])return target[key]},set(target,key,value){console.log(set,target,key,value)if(keydata){box.innerHTML value}target[key] value}
})观察者模式 作为总设计师会有许多手下他们都是看你办事你要是发出号令他们就得相应做出变化 一个被观察对象有许多观察者对象被观察者变化观察者发生相应变化。
class Sub {constructor() {this.observers []}add(observer) {this.observers.push(observer)}remove(observer) {this.observers this.observers.filter(item item ! observer)}notify() {this.observers.forEach(item item.update())}
}class Observer {constructor(name) {this.name name}update() {console.log(通知了, this.name)}
}
const observer1 new Observer(kerwin)
const observer2 new Observer(tiechui)const sub new Sub()
sub.add(observer1)
sub.add(observer2)setTimeout(() {sub.notify()
}, 2000)发布订阅模式 虽然作为总设计师有很大权利但总是有上级的上级有时会发布一些任务下来这些任务有的不是立即完成你可以记录下来。到了时候再完成即可。 观察者模式观察者和目标要相互知道 发布订阅模式发布者和订阅者不用互相知道通过第三方实现调度属于经过解耦合的观察者模式 class SubPub {constructor() {this.message {}//记录本}subscribe(type, fn) {if (!this.message[type]) {this.message[type] [fn]} else {this.message[type].push(fn)}}publish(type, ...arg) {if (!this.message[type]) returnconst event {type: type,arg: arg || {}}// 循环执行为当前事件类型订阅的所有事件处理函数this.message[type].forEach(item {item.call(this, event.arg)})}}与观者不同的是订阅的是事件而非对象,而且有不同的记录本记录不同的事 14. 模块化模式 模块化模式最初被定义为在传统软件工程中为类提供私有和公共封装的一种方法。
能够使一个单独的对象拥有公共/私有的方法和变量从而屏蔽来自全局作用域的特殊部分。这可以减少我们的函数名与在页面中其他脚本区域内定义的函数名冲突的可能性。 早前模块化是由闭包完成
var testModule (function () {var count 0;return {increment () {return count;},reset: function () {count 0;},decrement(){return --count;}};})();模块化
export default {name:moduleA,test(){return test}
}script typemoduleimport moduleA from ./1.jsconsole.log(moduleA)
/script迭代器模式 为遍历不同数据结构的 “集合” 提供统一的接口 能遍历访问 “集合” 数据中的项不关心项的数据结构
// 统一遍历接口实现
var kerwinEach function (arr, callBack) {for (let i 0; i arr.length; i) {callBack(i, arr[i])}
}// 外部调用
kerwinEach([11, 22, 33, 44, 55], function (index, value) {console.log([index, value]);var oli document.createElement(li)oli.innerHTML valuelist.appendChild(oli)
})指责链模式 Promise的then链式调用采用的就是这种模式 使多个对象都有机会处理请求从而避免了请求的发送者与多个接收者直接的耦合关系将这些接收者连接成一条链顺着这条链传递该请求直到找到能处理该请求的对象。
btn.addEventListener(click, function (event) {checks.check()
});function checkEmpty() {if (input.value.length 0) {console.log(这里不能为空);return}return next
}function checkNumber() {if (Number.isNaN(input.value)) {console.log(这里必须是数字);return}return next
}function checkLength() {if (input.value.length 6) {console.log(这里要大于6个数字);return}return next
}class Chain {constructor(fn) {this.checkRule fn || (() next);this.nextRule null;}addRule(nextRule) {this.nextRule new Chain(nextRule);return this.nextRule;//不断返回实例实现链式调用}end() {this.nextRule {check: () end};}check() {this.checkRule() next ? this.nextRule.check() : null;}
}const checks new Chain();
checks.addRule(checkEmpty).addRule(checkNumber).addRule(checkLength).end();最后还有一种不算设计模式但是非常有用的模式名为函数柯里化 试想一下你要打印一个日志它的内容是时间类型以及内容 很明显时间在一天中日期是不会变的类型也就那么几种唯独内容每次都不一样 但是前面两个参数只是不会频繁变化但却不能完全写死。 这时需要一个容器记住前面两个参数。大家可能会想到使用Object对象但是不要忘了函数也是对象合理利用函数闭包完全可以优雅的解决这个棘手的问题。
function logs(x){return function(y){return function(z){console.log(时间${x}类型${y}内容${z})}}
}
let logDatelogs(new Date().toLocaleDateString())//这个容器保存当天时间
let logDateErrorlogDate(error)//定义不同类型
let logDateSuccesslogDate(success)
let message1logDateError(错误信息1)//填写完全不同的内容
let message1logDateError(错误信息2)
let message2logDateSuccess(成功信息1)这样写logs函数大家可能担心陷入回调地狱凡是关于回调地狱都可以使用递归解决 自动封装函数
function currying(fn) {let curryFn function (...args) {if (args.length fn.length) {return fn(...args)} else {return function (...newArgs) {return curryFn(...args, ...newArgs)}}}return curryFn
}function test(a, b, c) {console.log(a, b, c)
}
var testCurrying currying(test)//放入该函数即可自动生成
testCurrying(1)(2)(3)
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/88717.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!