洪山网站建设公司,gl账号注册网站,网站开发主菜单和子菜单,品牌运营策划方案设计模式是我们在解决一些问题的时候 #xff0c;针对特定的问题给出的简介并且优化的处理方案
这篇文章说提及到的 JavaScript 设计模式将围绕着封装方法类来展开叙述
构造器模式
构造器模式本质就是我们平常在编码中常用的封装方法#xff0c;重复利用构造函数
// 这是…设计模式是我们在解决一些问题的时候 针对特定的问题给出的简介并且优化的处理方案
这篇文章说提及到的 JavaScript 设计模式将围绕着封装方法类来展开叙述
构造器模式
构造器模式本质就是我们平常在编码中常用的封装方法重复利用构造函数
// 这是一个简单的构造器我们创建实例的时候需要传递给他俩个参数这俩个参数就是它实例的属性
// 这个构造器中还有一个方法也就是它的实例所拥有的功能
function Constructors(user_name, user_age) {this.user_name user_namethis.user_age user_agethis.clickFunc () {console.log(${this.user_name}---${this.user_age})}
}// 我们创建了 Constructors 的实例
const Constructor_01 new Constructors(brave-airPig, 22)
const Constructor_02 new Constructors(airPig, 21)
// 我们使用通过 Constructors 构造器产生的实例的方法
Constructor_01.clickFunc()
Constructor_02.clickFunc()// brave-airPig---22
// airPig---21
看似没有问题的代码如果我们仔细观察会发现 clickFunc 方法在每次创建实例的时候创建这样一个相同的方法属实是没有必要的 我们有没有一种方法可以只创建一次该方法便可以让所有实例共享呢 原型模式
这次我们在构造器函数的原型上挂载该方法这样就不需要每次创建实例都创建一个方法去浪费内存了这里提到了一个关键字 prototype ,这是 JavaScript 语言中对象的原型我们直接挂载到其原型上这样就可以完美的解决这个问题了
function Constructors(user_name, user_age) {this.user_name user_namethis.user_age user_age
}Constructors.prototype.clickFunc function () {console.log(${this.user_name}--${this.user_age})
}const Constructor_01 new Constructors(brave-airPig, 22)
Constructor_01.clickFunc()// brave-airPig--22ES6类的写法 使用类的书写好像更好看逻辑更清楚一些类中的方法本身就是在其原型上的所以也不需要进行单独挂载了
class Constructors {constructor(user_name, user_age) {this.user_name user_namethis.user_age user_age}clickFunc() {console.log(${this.user_name}---${this.user_age})}
}const Constructor_01 new Constructors(brave-airPig, 22)
const Constructor_02 new Constructors(airPig, 21)
Constructor_01.clickFunc()
Constructor_02.clickFunc()在构造器与原型俩种模式的选择中我们的代码不知不觉就被优化了性能也相应提升了不少 工厂模式
工厂模式是由一个工厂对象决定创建某一种产品对象类的实例主要用来创建同一类对象也就是工厂的流水线生产出来的都是一摸一样的物品
我们只需要一个正确的参数即可获取到所需对象我们不需要知道创建的具体细节但是在函数内部包含了所有的创建逻辑以及代码每增加新的构造函数还需要修改判断逻辑代码当我们对象很多的时候这个工厂将会很庞大不好维护所以简单的工厂模式只能作用于创建的对象数量少对象的创建逻辑不复杂的时候使用
比如下面这个例子假如我们的系统有很多种客户角色每一种客户所能使用的功能和看到的内容是不一样的就像用户只能在系统中执行 func1 这个功能而超级管理员则可以在该系统中使用 4 个功能或者说是权限具体实现的话我们不用担心我们可以将这个功能数组进行循环创建 Tabbar 这样的话没有权限压根就看不到该 Tabbar也就无法点击以及使用其中的功能了
function UserFactory(role) {function User(role, pages) {this.role rolethis.pages pages}switch (role) {case superadmin:return new User(超级管理员, [fun1, fun2, fun3, fun4])case admin:return new User(管理员, [fun1, fun2, fun3])case loweradmin:return new User(低级管理员, [fun1, fun2])case users:return new User(用户, [fun1])default:throw new Error(参数错误)}
}console.log(UserFactory(users))
console.log(UserFactory(superadmin))// User { role: 用户, pages: [ fun1 ] }
// User { role: 超级管理员, pages: [ fun1, fun2, fun3, fun4 ] }这样我们就可以根据对应的身份去做对应的权限分配了
ES6写法
class User {constructor(role, pages) {this.role rolethis.pages pages}static UserFactory(role) {switch (role) {case superadmin:return new User(超级管理员, [fun1, fun2, fun3, fun4])case admin:return new User(管理员, [fun1, fun2, fun3])case loweradmin:return new User(低级管理员, [fun1, fun2])case users:return new User(用户, [fun1])default:throw new Error(参数错误)}}
}console.log(User.UserFactory(users))
console.log(User.UserFactory(superadmin))// User { role: 用户, pages: [ fun1 ] }
// User { role: 超级管理员, pages: [ fun1, fun2, fun3, fun4 ] }抽象工厂模式
这也是针对工厂模式无法应对多对象多复杂对象而出的一种模式抽象工厂模式并不是直接生成实例而是对于产品的一个分类的创建
// 抽象父类
class User {constructor(name, role, pages) {this.name namethis.role rolethis.pages pages}//登录功能login() {console.log(尊敬的${this.name},欢迎回来)}// 指定用户权限对应显示的数据dataShow() {throw new Error(请实现抽象方法)}
}// 超级管理员子类继承 User 父类
class SupeRadmin extends User {constructor(name) {super(name, superadmin, [fun1, fun2, fun3, fun4])}dataShow() {console.log(超级管理员可视数据)}addTest() {console.log(超级管理员独有的方法)}
}// 管理员子类继承 User 父类
class Admin extends User {constructor(name) {super(name, admin, [fun1, fun2, fun3])}dataShow() {console.log(管理员可视数据)}
}// 低级管理员子类继承 User 父类
class LowerRadmin extends User {constructor(name) {super(name, loweradmin, [fun1, fun2])}dataShow() {console.log(低级管理员可视数据)}
}// 普通用户子类继承 User 父类
class Users extends User {constructor(name) {super(name, users, [fun1])}dataShow() {console.log(用户可视数据)}usersTest() {console.log(用户特有方法)}
}// 构造方法通过这个鉴权方法来判定我们应该实例化那个子类或者说实例然后展现对应权限的数据以及实现相应的功能
function getAbstractUserFactory(role) {switch (role) {case superadmin:return new SupeRadmin(超级管理员)case admin:return new Admin(管理员)case loweradmin:return new LowerRadmin(低级管理员)case users:return new Users(用户)default:throw new Error(参数错误)}
}console.log(getAbstractUserFactory(superadmin))
getAbstractUserFactory(users).login()
getAbstractUserFactory(loweradmin).login()
getAbstractUserFactory(superadmin).addTest()// SupeRadmin {
// name: 超级管理员,
// role: superadmin,
// pages: [ fun1, fun2, fun3, fun4 ]
// }
// 尊敬的用户,欢迎回来
// 尊敬的低级管理员,欢迎回来
// 超级管理员独有的方法建造者模式
建造者模式是属于创建型模式的一种提供了一种创建复杂对象的方式它将一个复杂的对象的构建与它的表示分离开来使得同样的构建过程可以创建不同的表示
构建者模式是通过一步一步的创建一个复杂对象允许用户只通过指定复杂对象的类型和内容就可以构建它们用户无需指定内部的具体构造细节
// 模拟navbar选项卡的选项与数据从初始化到渲染到视图的简单生命周期
class Navbar {// 初始化init() {console.log(初始化)}getData() {// 模拟ajax异步请求数据return new Promise((resolve) {setTimeout(() {resolve()console.log(请求数据成功)}, 1500)})}// 将数据渲染到视图render() {console.log(渲染)}
}class List {// 初始化init() {console.log(初始化)}getData() {// 模拟ajax异步请求数据return new Promise((resolve) {setTimeout(() {resolve()console.log(请求数据成功)}, 1500)})}// 将数据渲染到视图render() {console.log(渲染)}
}const navbar new Navbar()
const list new List()// 建造者
class Operator {async startBuild(build) {await build.init()await build.getData()await build.render()}
}const op new Operator()
op.startBuild(navbar)
op.startBuild(list)// 初始化
// 初始化
// 请求数据成功
// 渲染
// 请求数据成功
// 渲染单例模式
单例模式保证一个类仅有一个实例并且提供一个访问它的全局访问点解决全局使用的类频繁的创建和销毁占用内存
ES5构建方法闭包
function User(user_name, user_age) {this.user_name user_namethis.user_age user_age
}let singleton (function () {// 使用闭包让 GC 不会回收该变量 那么该变量也就理所应当的成为了全局变量let instance nullreturn function (user_name, user_age) {if (!instance) instance new User(user_name, user_age)return instance}
})()console.log(singleton(airpig, 22))
console.log(singleton(pig, 21))// User { user_name: airpig, user_age: 22 }
// User { user_name: airpig, user_age: 22 }
ES6 实现
class Singleton {constructor(user_name, user_age) {if (!Singleton.instance) {this.user_name user_namethis.user_age user_ageSingleton.instance this}return Singleton.instance}
}console.log(new Singleton(airpig, 22))
console.log(new Singleton(pig, 21))// Singleton { user_name: airpig, user_age: 22 }
// Singleton { user_name: airpig, user_age: 22 }装饰器模式
装饰器模式能够很好的对已有功能进行拓展也就是 ”锦上添花“ 的意思
它不会更改原有代码、对其他的业务产生印象、方便我们在较少的改动之下对软件功能进行拓展
Function.prototype.before function (beforeFunc) {let _this thisreturn function () {beforeFunc.apply(this, arguments)return _this.apply(this, arguments)}
}Function.prototype.after function (afterFunc) {let _this thisreturn function () {const fn _this.apply(this, arguments)afterFunc.apply(this, arguments)return fn}
}const testFunc () {console.log(这是一个测试方法)return 测试方法
}const addTest testFunc.before(() {console.log(测试方法之前执行)}).after(() {console.log(测试方法之后执行)})console.log(testFunc())
console.log(--------------)
console.log(addTest())// 这是一个测试方法
// 测试方法
// --------------
// 测试方法之前执行
// 这是一个测试方法
// 测试方法之后执行
// 测试方法适配器模式
适配器不会去改变实现层、实现层不属于它的职责范围它干涉了抽象过程外部接口的适配能够让同一个方法适用于多种系统也就是说它会将一个类的接口转换成客户希望的另一个接口适配器模式让那些接口不兼容的类可以一起工作
// 腾讯地图
class TencentMap {TencentMapShow() {console.log(显示腾讯地图)}
}class BaiduMap {BaiduMapShow() {console.log(显示百度地图)}
}// 适配器class TencentMapAdapter extends TencentMap {constructor() {super()}// 渲染render() {this.TencentMapShow()}
}class BaiduMapAdapter extends BaiduMap {constructor() {super()}// 渲染render() {this.BaiduMapShow()}
}// 使用者const renderMap (mapStyle) mapStyle.render()// 调用地图let userP IQQOif (!userP IQQO) renderMap(new TencentMapAdapter())
else renderMap(new BaiduMapAdapter())策略模式
策略模式定义了一系列算法并将每一个算法封装起来。使他们可以相互的替换并且算法的变化不会影响使用算法的客户策略模式属于对象行为模式它通过对算法进行封装把使用算法的责任和算法的实现分隔开来并委派给不同的对象对这些算法进行管理
该模式主要用来解决多种算法相似的情况下的优化使用 if...else 所带来的复杂和难以维护使用这种模式即可以解决算法可以自由进行切换同时可避免多重 if...else 判断并具有良好的扩展性
let policy {A: (multiple) multiple * 100,B: (multiple) multiple * 10,C: (multiple) multiple * 2,
}const numPolicy (lv, multiple) policy[lv](multiple)console.log(numPolicy(C, 200))
console.log(numPolicy(B, 50))
console.log(numPolicy(A, 60))// 400
// 500
// 6000代理模式
代理模式是为其他对象提供一种代理以控制对这个对象的访问使得代理对象控制具体对象的引用代理几乎可以是任何对象
// 名为 airPig 的员工跳槽记
let user {name: airPig,deposit: 2500,
}let proxy new Proxy(user, {// 访问对象将执行 get 方法 -- 模拟去新公司面试get(target, key) {if (key deposit)console.log(新公司问你之前工资多少 -- 你回答了 target[key])if (key name)console.log(新公司问你名字 -- 你回答了 target[key])return target[key]},// 修改对象属性 执行 set 方法 -- 修改你的工资set(target, key, value) {if (key deposit) {console.log(将要修改你的工资)if (value target[deposit])console.log(修改成功 -- 现在工资为 value)else throw new Error(跳槽不能把工资往小修改)}},
})// proxy.name 新公司问你名字 -- 你回答了airPig
// proxy.deposit 新公司问你之前工资多少 -- 你回答了2500
// proxy.deposit 1500 Error: 不能往小修改// proxy.deposit 24000
// 已被修改
// 修改成功 -- 现在工资为24000 观察者模式
观察者模式包含观察目标和观察者俩类对象一个目标可以有任意数目的与之相依赖的观察者一旦观察目标的状态发生了变化那么所有的观察者也将得到通知
当一个对象的状态发生变化的时候所有的依赖与它的对象都将得到通知并被自动更新、解决了主题对象与观察者之间功能的耦合即一个对象状态该改变通知其他对象
这个模式的有点在于目标者与观察者功能的耦合度降低可以专注自身功能逻辑观察者将被动接受更新在时间上解耦实时目标者更新状态不过没有一种模式是完美无缺的什么场景都合适的它的缺点是虽然实现了对象之间的依赖关系解耦合但是却不能对事件通知进行细分管理如筛选通知、指定主题事件通知等等
class Subject {constructor() {this.observer []}// 添加观察者addObserver (observer) this.observer.push(observer)// 删除观察者removeObserver (observer) (this.observer this.observer.filter((item) item ! observer))// 通知观察者更新notify () this.observer.forEach((item) item.update())
}class Observer {constructor(name) {this.name name}update () console.log(update -- 观察者更新了, this.name)
}const subject new Subject()
const observer1 new Observer(观察者1号)
const observer2 new Observer(观察者2号)
const observer3 new Observer(观察者3号)
const observer4 new Observer(观察者4号)subject.addObserver(observer1)
subject.addObserver(observer2)
subject.addObserver(observer3)
subject.addObserver(observer4)subject.notify()
console.log(-------------)
subject.removeObserver(observer1)
subject.notify()// update -- 观察者更新了 观察者1号
// update -- 观察者更新了 观察者2号
// update -- 观察者更新了 观察者3号
// update -- 观察者更新了 观察者4号
// -------------
// update -- 观察者更新了 观察者2号
// update -- 观察者更新了 观察者3号
// update -- 观察者更新了 观察者4号 发布订阅者模式
发布订阅者模式与观察者模式很是相似不过它们却有着本质的区别
观察者和目标者需要相互知晓
发布者和订阅者不需要相互知晓它们是通过第三方来实现调度的属于经过解耦合的观察者模式
const SUBSCRIBER {message: {},// 发布订阅消息publish(type, data) {if (!this.message[type]) returnthis.message[type].forEach((item) item(data))},// 添加订阅者subscribe(type, fn) {if (!this.message[type]) this.message[type] [fn]else this.message[type].push(fn)},// 删除订阅者unsubscribe(type, fn) {if (!this.message[type]) return// 没有指定删除订阅者就删除全部订阅者if (!fn) this.message[type] (this.message[type].length 0)else this.message[type] this.message[type].filter((item) item ! fn)},
}let test_01 (data) console.log(test_01, data)
let test_02 (data) console.log(test_02, data)
let test_03 (data) console.log(test_03, data)
let test_04 (data) console.log(test_04, data)SUBSCRIBER.subscribe(A, test_01)
SUBSCRIBER.subscribe(B, test_02)
SUBSCRIBER.subscribe(A, test_03)
SUBSCRIBER.subscribe(C, test_04)// 发新闻
SUBSCRIBER.publish(A, 专属订阅A的早报)
SUBSCRIBER.publish(B, 这是给B订阅者的晚报)// 取消订阅
SUBSCRIBER.unsubscribe(C, test_04)SUBSCRIBER.publish(C, 发给C订阅者的报纸)// 删除所有订阅
SUBSCRIBER.unsubscribe(A)SUBSCRIBER.publish(A, 专属订阅A的早报)// test_01 专属订阅A的早报
// test_03 专属订阅A的早报
// test_02 这是给B订阅者的晚报 模块模式
模块化模式最初被定义为在传统的软件工程中为类提供私有和公共封装的一种方法能够使一个单独的对象拥有公共或者私有的方法和变量从而屏蔽来自全局作用域的特殊部分这可以减少我们的函数名与在页面中其他脚本或者作用域内定义的函数名冲突的可能性不过在ES6提出块级作用域的时候就解决了这个问题了
并且在 ES6 中的模块化导入导出也是很好的支持了这个模块化模式或者我们使用 ES6 类的时候也可以使用 # 来声明一个私有变量
那么 ES6 之前我们都是怎么解决的呢没错就是闭包,闭包会使函数作用域一直存在其中的私有变量也不会出现被 CG
var testMoudle (function () {var count 0return {increment: function () {return count},reset: function () {count 0},decrement() {return --count},}
})()console.log(testMoudle.increment())
console.log(testMoudle.decrement())
testMoudle.reset()
console.log(testMoudle.decrement())
console.log(count)// 1
// 0
// - 1
// count is not defined
ES6 模块化导入导出
let count 0const increase () count
const decrease () --count
const reset () {count 0
}export default {increase,decrease,reset,
}// 只导出三个方法变量该脚本私有!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headbodyscript typemoduleimport MyModule from ./module_export.jsconsole.log(MyModule)/script/body
/html 第二种导出导入方法
let count 0const increase () count
const decrease () --count
const reset () {count 0
}export { increase, decrease, reset }// 只导出三个方法变量该脚本私有
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headbodyscript typemoduleimport { increase, decrease, reset } from ./module_export.jsconsole.log(increase(), decrease())/script/body
/html桥接模式
桥接模式就是将抽象部分与它的实现部分进行分离使它们都可以独立的变化一个类存在俩个或者多个独立变化的维度并且这俩个维度都需要进行扩展有助于独立的管理各组成部分缺点是每使用一个桥接元素都要增加一次函数的调用性能降低提高系统复杂程度
// 模态框的动作
class Toast {constructor(ele, animation) {this.ele elethis.animation animation}show() {this.animation.show(this.ele)}hide() {this.animation.hide(this.ele)}
}const ANIMATIONS {bounce: {show: (ele) console.log(${ele}元素弹跳显示),hide: (ele) console.log(${ele}元素弹跳隐藏),},silde: {show: (ele) console.log(${ele}元素滑动显示),hide: (ele) console.log(${ele}元素滑动隐藏),},
}let toast new Toast(#box, ANIMATIONS.silde)toast.show()
toast.hide()let toast2 new Toast(.div, ANIMATIONS.bounce)toast2.show()
toast2.hide()// #box元素滑动显示
// #box元素滑动隐藏
// .div元素弹跳显示
// .div元素弹跳隐藏组合模式
组合模式就是在对象间形成一个树形结构组合模式中基本对象和组合对象被一致对待我们不需要去关心对象有多少层调用的时候只需要在根部进行一个调用它模糊了简单元素和复杂元素的概念客户程序可以像处理简单元素一样去处理复杂元素从而使得客户程序与复杂元素的内部结构进行一个解耦
const FOLDER function (folder) {this.folder folderthis.list []
}FOLDER.prototype.addFunc function (res) {this.list.push(res)
}FOLDER.prototype.scanFunc function () {console.log(扫描 ${this.folder} 文件)for (let i 0; i this.list.length; i) {this.list[i].scanFunc()}
}const FILE function (file) {this.file file
}FILE.prototype.scanFunc function () {console.log(开始扫描${this.file}文件)
}const Folder new FOLDER(root)let folder_02 new FOLDER(src)
let folder_03 new FOLDER(components)
let folder_04 new FOLDER(public)
let folder_05 new FOLDER(images)let file_01 new FILE(test_01.js)
let file_02 new FILE(test_02.js)
let file_03 new FILE(test_01.jsx)
let file_04 new FILE(test_01.html)
let file_05 new FILE(test_01.jpg)Folder.addFunc(folder_02)
Folder.addFunc(folder_03)
Folder.addFunc(folder_04)
Folder.addFunc(folder_05)folder_02.addFunc(file_01)
folder_02.addFunc(file_02)
folder_03.addFunc(file_03)
folder_04.addFunc(file_04)
folder_05.addFunc(file_05)Folder.scanFunc()// 扫描 root 文件
// 扫描 src 文件
// 开始扫描test_01.js文件
// 开始扫描test_02.js文件
// 扫描 components 文件
// 开始扫描test_01.jsx文件
// 扫描 public 文件
// 开始扫描test_01.html文件
// 扫描 images 文件
// 开始扫描test_01.jpg文件 命令模式
有时我们需要向某些对象发送请求但是并不知道请求的接收者是谁也不知道被请求的操作是什么需要一种松耦合的方式来设计程序使得发送者和接受者能够消除彼此之间的耦合
发布者发出命令调用命令对象不知道如何执行与谁执行接收者提供对应接口处理请求不知道谁发起的请求命令对象接受命令。调用接收者对应的接口处理发布者的请求
// 接收者
class Receiver {execute() {console.log(接收者执行请求)}
}// 命令对象
class Command {constructor(receiver) {this.receiver receiver}execute() {console.log(命令对象 -- 接收者 -- 对应接口执行)this.receiver.execute()}
}// 发布者
class Invoker {constructor(command) {this.command command}invoker() {console.log(发布者发布请求)this.command.execute()}
}let store_house new Receiver()
let order new Command(store_house)
let client new Invoker(order)client.invoker()// 发布者发布请求
// 命令对象 -- 接收者 -- 对应接口执行
// 接收者执行请求 模板方法模式
模板方法模式由俩部分组成第一部分是抽象父类第二部分是具体实现子类通常在抽象父类中封装了子类的算法框架包括实现一些公共方法以及封装子类中所有方法的执行顺序子类通过继承这个抽象类也继承了整个算法结构并且可以选择重写父类方法它是一种典型的通过封装变化提高系统扩展性的设计模式运用了模板方法模式的程度中子类方法种类和执行顺序都是不变的但是子类的方法具体实现则是可变的父类只是一个模板子类可以添加不同的功能
let Container function (param) {this.render function (list) {console.log(渲染列表, list)}let getData param.getData ||function () {throw new Error(必须传递getData方法)}let func new Function()func.prototype.init async function () {let list await getData()render(list)}return func
}let Nowplaying Container({getData: () [1, 2, 3],
})
let nowplaying new Nowplaying()
nowplaying.init()let Commimgsoon Container({getData: () [4, 5, 6],
})
let commingsoon new Commimgsoon()commingsoon.init()// 渲染列表 [ 1, 2, 3 ]
// 渲染列表 [ 4, 5, 6 ]迭代器模式
迭代器模式是指提供一种方法顺序访问一个聚合对象中的各个元素而又不需要暴露该对象的内部表示迭代器模式可以把迭代的过程从业务逻辑中分离出来在使用迭代器模式之后即使不关心对象的内部构造也可以按照顺序访问其中的每个元素
// 统一接口
let MyEach function (arr, callback) {for (let i 0; i arr.length; i) {callback(i, arr[i])}
}// 外部调用
MyEach([1, 2, 3, 4, 5, 6, 7, 8, 9], (index, value) {console.log(index, value)
})// 0 1
// 1 2
// 2 3
// 3 4
// 4 5
// 5 6
// 6 7
// 7 8
// 8 9ES6中数组等等支持了迭代器如果我们想让对象使用迭代器的话
let obj {0: test_01,1: test_02,2: test_03,3: test_04,4: test_05,5: test_06,6: test_07,7: test_08,8: test_09,length: 9,[Symbol.iterator]: Array.prototype[Symbol.iterator],
}for (let item of obj) {console.log(item)
}// test_01
// test_02
// test_03
// test_04
// test_05
// test_06
// test_07
// test_08
// test_09上面我们的对象使用的是数组的迭代器让我们继续手写一个精巧的迭代器
let obj {list: [1, 2, 3, 4, 5, 6, 7, 8, 9],[Symbol.iterator]: function () {let index 0return {next: () {if (index this.list.length) {return { value: this.list[index], done: false }} else {return { value: undefined, done: true }}},}},
}
let a obj[Symbol.iterator]()
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())
console.log(a.next())// { value: 1, done: false }
// { value: 2, done: false }
// { value: 3, done: false }
// { value: 4, done: false }
// { value: 5, done: false }
// { value: 6, done: false }
// { value: 7, done: false }
// { value: 8, done: false }
// { value: 9, done: false }
// { value: undefined, done: true }
// { value: undefined, done: true }
// { value: undefined, done: true }
// { value: undefined, done: true }职责链模式
使多个对象都有机会处理请求从而避免了请求的发送者与多个接收者直接的耦合关系将这些接受连接成一条链顺着这条链传递该请求知道找到能处理该请求的对象
这种模式符合单一原则使每个方法都只有一个职责符合开放封闭原则在需求增加时可以很方便的扩充新责任使用时也无需知晓谁是真正的处理方法减少了大量的 if 以及 switch 循环判断语句
这种模式的缺点是团队成员需要对责任链存在共识也就是说这个模式写上别人不容易看懂排查错误也是不容易的
!DOCTYPE html
html langenheadmeta charsetUTF-8 /meta http-equivX-UA-Compatible contentIEedge /meta nameviewport contentwidthdevice-width, initial-scale1.0 /titleDocument/title/headbodyinput typetext placeholder输入符合条件的密码 /button确认/buttonscriptconst ipt document.querySelector(input)const btn document.querySelector(button)btn.addEventListener(click, () {checks.check()})function checkEmpty() {if (!ipt.value.trim()) {console.log(不能为空)return}return next}function checkNumber() {if (Number.isNaN(ipt.value)) {console.log(只能为数字)return}return next}function checkLength() {if (ipt.value.length 8) {console.log(必须大于 8 位)return}return next}///class Chain {constructor(func) {this.checkRule func || (() 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()/script/body
/html 结束了
这么快就结尾了我想说我们不要为了使用设计模式而去使用设计模式有时候根本没必要有时候会画蛇添足如果使用设计模式可以给你带来代码的整洁可维护或者业务上的性能提升那么在这个时候我们可以适当考虑使用设计模式它很棒