模块模式

在立即执行函数表达式中定义的变量和方法在外界是访问不到的,只能通过其向外部提供的接口,"有限制"地访问.通过函数作用域解决了属性和方法的封装问题.

var Person = (function(){var name = "dx";var age = 22;function getName(){return name;}function getAge(){return age;}return {getName: getName,getAge: getAge}
})();console.log(age); // 报错:age未定义
console.log(name); // 报错:name未定义
console.log(Person.age); // undefined
console.log(Person.name); // undefined
// 只能通过Person提供的接口访问相应的变量
console.log(Person.getName()); // dx
console.log(Person.getAge()); // 22

构造函数模式

function Person(name,age){this.name = name;this.age = age;
}
Person.prototype = {constructor: Person;printName: function(){console.log(this.name);},printAge: function(){console.log(this.age);}
}var person = new Person('dx', 22);
person.printName(); // dx
person.printAge(); // 22

单例模式

无论执行多少次,返回的始终都是同一个对象或实例。

// 构造函数
function Person(name,age) {this.name = name;this.age = age;this.setName = (changeName) => {this.name = changeName}
}
Person.prototype.getName = function () {return this.name
}// 单例模式函数(自执行函数,将return的函数赋给singletonMode)
let singletonMode = (function () {let instance = null;return function (name, age) {if (!instance) {instance = new Person(name, age)}return instance}
})()const person1 = new singletonMode('dx', 18)
console.log(person1.getName()) // dx
const person2 = new singletonMode('yx', 18)
console.log(person2.getName()) // dxperson1.setName('yx')
console.log(person1.getName()) // yx
console.log(person2.getName()) // yx// person1和person2始终是同一个实例
console.log(person1 === person2) // true

工厂模式

什么场景适合应用工厂模式而不是直接 new 一个对象呢?当构造函数过多不方便管理,且需要创建的对象之间存在某些关联(有同一个父类、实现同一个接口等)时,不妨使用工厂模式。工厂模式提供一种集中化、统一化的方式,避免了分散创建对象导致的代码重复、灵活性差的问题。

// 汽车构造函数
function SuzukiCar(color) {this.color = color;this.brand = 'Suzuki';
}// 汽车构造函数
function HondaCar(color) {this.color = color;this.brand = 'Honda';
}// 汽车构造函数
function BMWCar(color) {this.color = color;this.brand = 'BMW';
}// 汽车品牌枚举
const BRANDS = {suzuki: 1,honda: 2,bmw: 3
}/*** 汽车工厂*/
function CarFactory() {this.create = function (brand, color) {switch (brand) {case BRANDS.suzuki:return new SuzukiCar(color);case BRANDS.honda:return new HondaCar(color);case BRANDS.bmw:return new BMWCar(color);default:break;}}
}

观察者模式 (发布订阅模式)

被观察对象(subject)维护一组观察者(observer),当被观察对象状态改变时,通过调用观察者的某个方法将这些变化通知到观察者。

比如给DOM元素绑定事件的 addEventListener() 方法:

target.addEventListener(type, listener [, options]);
Target就是被观察对象Subject,listener就是观察者Observer。

观察者模式中Subject对象一般需要实现以下API:

subscribe(): 接收一个观察者observer对象,使其订阅自己
unsubscribe(): 接收一个观察者observer对象,使其取消订阅自己
fire(): 触发事件,通知到所有观察者

// 观察者
function Observer({name,...args}, callback) {this.name = name;this.data = {...args};this.callback = callback
}// 被观察者
function Subject() {this.observers = [];
}Subject.prototype = {// 订阅subscribe: function (observer) {this.observers.push(observer);},// 取消订阅unsubscribe: function (observerToRemove) {this.observers = this.observers.filter(observer => {return observer.name !== observerToRemove.name;})},// 事件触发fire: function () {this.observers.forEach(observer => {observer.callback ();});}
}// 创建一个被观察的实例
const Subject1 = new Subject()// 创建一个观察者实例
const Observer1 =  new Observer({name: 'onClick', otherArguments: {...}}, function() {console.log(this.name, this.otherArguments)
} )const Observer2 = new Observer({name: 'onMouseMove', otherArguments: {...}}, function() {console.log(this.name, this.otherArguments)
} )// 在需要的时候订阅
Subject1.subscribe(Observer1)
Subject1.subscribe(onMouseMove)
// 在需要的时候取消订阅
Subject1.unsubscribe(Observer1)// 在被观察者发生改变时,触发
Subject1.fire()

代理模式

当访问一个对象本身的代价太高(比如太占内存、初始化时间太长等)或者需要增加额外的逻辑又不修改对象本身时便可以使用代理。ES6中也增加了 Proxy 的功能。

  1. 增加对一个对象的访问控制
  2. 当访问一个对象的过程中需要增加额外的逻辑

Real Subject:真实对象
Proxy:代理对象
Subject接口:Real Subject 的方法或者属性,Proxy都需要去实现,这样Proxy才能被当成Real Subject的“替身”使用

Real Subject ---- StockPriceAPI

function StockPriceAPI() {// Subject Interface实现this.getValue = function (stock, callback) {console.log('Calling external API ... ');setTimeout(() => {switch (stock) {case 'GOOGL':callback('$1265.23');break;case 'AAPL':callback('$287.05');break;case 'MSFT':callback('$173.70');break;default:callback('');}}, 2000);}
}

Proxy ----- StockPriceAPIProxy

我们不希望每次都去请求远程接口,而是增加缓存机制,当有缓存的时候就直接从缓存中获取,否则再去请求远程接口。我们可以通过一个proxy来实现:

function StockPriceAPIProxy() {// 缓存对象this.cache = {};// 真实API对象this.realAPI = new StockPriceAPI();// Subject Interface实现this.getValue = function (stock, callback) {const cachedPrice = this.cache[stock];if (cachedPrice) {console.log('Got price from cache');callback(cachedPrice);} else {this.realAPI.getValue(stock, (price) => {this.cache[stock] = price;callback(price);});}}
}

Proxy需要和真实对象一样实现 getValue() 方法,

const api = new StockPriceAPIProxy();
api.getValue('GOOGL', (price) => { console.log(price) });
api.getValue('AAPL', (price) => { console.log(price) });
api.getValue('MSFT', (price) => { console.log(price) });setTimeout(() => {api.getValue('GOOGL', (price) => { console.log(price) });api.getValue('AAPL', (price) => { console.log(price) });api.getValue('MSFT', (price) => { console.log(price) });
}, 3000)
Calling external API ...
Calling external API ...
Calling external API ...
$1265.23
$287.05
$173.70
Got price from cache
$1265.23
Got price from cache
$287.05
Got price from cache
$173.70

迭代器模式

  1. 提供一致的遍历各种数据结构的方式,而不用了解数据的内部结构
  2. 提供遍历容器(集合)的能力而无需改变容器的接口

hasNext():判断迭代是否结束,返回Boolean
next():查找并返回下一个元素

const item = [{value: 1}, {value: 'red'}, {value: 'false'}, {value: 3.14}];function Iterator(items) {this.items = items;this.index = 0;
}Iterator.prototype = {hasNext: function () {return this.index < this.items.length;},next: function () {return this.items[this.index++].value;}
}// 验证一下
const iterator = new Iterator(item);while(iterator.hasNext()){console.log(iterator.next());
}// 1, red, false, 3.14

ES6提供了更简单的迭代循环语法 for…of,使用该语法的前提是操作对象需要实现 可迭代协议(The iterable protocol),简单说就是该对象有个Key为 Symbol.iterator 的方法,该方法返回一个iterator对象。

function Range(start, end) {return {[Symbol.iterator]: function () {return {next() {if (start < end) {return { value: start++, done: false };}return { done: true, value: end };}}}}
}for (num of Range(1, 5)) {console.log(num);
}// 1, 2, 3, 4

中介者模式(Mediator Pattern)

中介者模式中,中介者(Mediator)包装了一系列对象相互作用的方式,使得这些对象不必直接相互作用,而是由中介者协调它们之间的交互,从而使它们可以松散偶合。当某些对象之间的作用发生改变时,不会立即影响其他的一些对象之间的作用,保证这些作用可以彼此独立的变化。

中介者模式有些像婚恋中介,相亲对象刚开始并不能直接交流,而是要通过中介去筛选匹配再决定谁和谁见面。中介者模式比较常见的应用比如聊天室,聊天室里面的人之间并不能直接对话,而是通过聊天室这一媒介进行转发。一个简易的聊天室模型可以实现如下:

聊天室成员类:

function Member(name) {this.name = name;this.chatroom = null;
}Member.prototype = {// 发送消息send: function (message, toMember) {this.chatroom.send(message, this, toMember);},// 接收消息receive: function (message, fromMember) {console.log(`${fromMember.name} to ${this.name}: ${message}`);}
}

聊天室类:

function Chatroom() {this.members = {};
}Chatroom.prototype = {// 增加成员addMember: function (member) {this.members[member.name] = member;member.chatroom = this;},// 发送消息send: function (message, fromMember, toMember) {toMember.receive(message, fromMember);}
}

所有聊天室成员发送的消息都是由成员调用聊天室的send方法,聊天室来调用对应成员的recevice方法来实现接收的。

所有发出的消息都需要经过聊天室统一处理,聊天室就是中介。

访问者模式

访问者模式让我们能够在不改变一个对象结构的前提下能够给该对象增加新的逻辑或者方法。
访问者模式常用于拓展一些第三方的库和工具。

一个可以通过 accep来拓展逻辑 的 某构造函数

function Employee(name, salary) {this.name = name;this.salary = salary;
}Employee.prototype = {getSalary: function () {return this.salary;},setSalary: function (salary) {this.salary = salary;},accept: function (visitor) {visitor.visit(this);}
}

一个专门针对 Employee实例对象的访问者,并添加对应的逻辑。

function Visitor() { }Visitor.prototype = {visit: function (employee) {employee.setSalary(employee.getSalary() * 2);}
}

如何使用

const employee = new Employee('bruce', 1000);
const visitor = new Visitor();
employee.accept(visitor);console.log(employee.getSalary());// 2000

策略模式

定义:策略模式就是将一系列算法封装起来,并使它们相互之间可以替换。被封装起来的算法具有独立性,外部不可改变其特性。(简单的说减少if判断,改成switch的理念)

目的:将算法的使用与算法的实现分离开来

优点:
顾名思义:策略即选择,当存在大量的选择判断时,可以采取策略模式,将不同的方法抽离封装,将一个个方法封装起来,提高代码复用率,减少代码冗余;策略模式可看作为if/else判断的另一种表现形式,在达到相同目的的同时,极大的减少了代码量以及代码维护成本。

let calculateByRank = ( experience,vipRank ) => {if(vipRank==='0'){return experience;}else if(vipRank==='1'){return experience*1.5;}else if(vipRank==='2'){return experience*2;}else if(vipRank==='3'){return experience*2.5;}else if(vipRank==='4'){return experience*3;}}

策略模式进行改造


let calculateByRank = ( experience,vipRank ) => {return calculateObject[vipRank](experience);
}let calculateObject = {"vipRank0":function ( experience ){return experience;},"vipRank1":function ( experience ){return experience*1.5;},"vipRank2":function ( experience ){return experience*2;},"vipRank3":function ( experience ){return experience*2.5;},      "vipRank4":function ( experience ){return experience*3;}
}

js 常用设计模式(1024过节礼物)相关推荐

  1. JS常用的设计模式(7)—— 外观模式

    JS常用的设计模式(7)-- 外观模式 外观模式(门面模式),是一种相对简单而又无处不在的模式.外观模式提供一个高层接口,这个接口使得客户端或子系统更加方便调用. 用一段再简单不过的代码来表示 var ...

  2. JS常用的设计模式(2)——简单工厂模式

    JS常用的设计模式(2)--简单工厂模式 简单工厂模式是由一个方法来决定到底要创建哪个类的实例, 而这些实例经常都拥有相同的接口. 这种模式主要用在所实例化的类型在编译期并不能确定, 而是在执行期决定 ...

  3. JS 常用的六种设计模式介绍

    常用设计模式 前言 我们经常听到一句话,"写代码要有良好的封装,要高内聚,低耦合".究竟怎样的代码才算得上是良好的代码. 什么是高内聚,低耦合? 即五大基本原则(SOLID)的简写 ...

  4. 7 种 Javascript 常用设计模式学习笔记

    7 种 Javascript 常用设计模式学习笔记 由于 JS 或者前端的场景限制,并不是 23 种设计模式都常用. 有的是没有使用场景,有的模式使用场景非常少,所以只是列举 7 个常见的模式 本文的 ...

  5. 原型模式的应用场景_前端常用设计模式

    求关注 前端常见的设计模式主要有以下几种:1. 单例模式2. 工厂模式3. 策略模式4. 代理模式5. 观察者模式6. 模块模式7. 构造函数模式8. 混合模式 单例模式 这种设计模式的思想是确保一个 ...

  6. 第60天:js常用访问CSS属性的方法

    一. js 常用访问CSS 属性的方法 我们访问得到css 属性,比较常用的有两种: 1. 利用点语法  box.style.width      box.style.top     点语法可以得到 ...

  7. Atitit.跨语言 java c#.net php js常用的codec encode算法api 兼容性  应该内置到语言里面...

    Atitit.跨语言 java c#.net php js常用的codec encode算法api 兼容性  应该内置到语言里面 1. 常用算法1 1.1. 目录2 1.2. 定义和用法编辑2 1.3 ...

  8. prototype.js常用函数及其用法

    prototype.js常用函数: 函数名  解释  举例  Element.toggle  交替隐藏或显示  Element.toggle(''div1'',''div2'')  Element.h ...

  9. 打死都要记住!微服务架构的常用设计模式!

    作者:duanxz 来源:cnblogs.com/duanxz/p/3514895.html 大家好,我每天都会在这里给大家分享一些干货内容(当然了,周末也要允许我休息一下哈).今天跟大家分享微服务架 ...

最新文章

  1. MVC3.0删除数据的时候给提示信息
  2. 【实用】客户行项目清单FBL5N增加利润中心
  3. 【Android】使用Assets目录中的图片资源
  4. spring手动回滚
  5. 变动性算法源代码分析与使用示例(copy_backward、 transform、 replace_copy_if 等)
  6. 《Android深入透析》之界面
  7. Non-Rigid Registration Under Isometric Deformations
  8. e7用什么主板_主板当中的纽扣电池有什么用?电池没电了会怎样?
  9. 江苏省级计算机一级b理论,江苏省计算机一级B理论部分复习资料.doc
  10. 使用winRAR脚本bat,需要的参数
  11. 系统辨识(一):相关概念
  12. android SoundPool例子,Android SoundPool即时音效的使用Demo
  13. 单片机c语言延时1ms函数,单片机c语言延时函数用int与char有延时差吗?
  14. MTK平台的srvcc相关故障
  15. 硅谷裁员潮下的华人码农
  16. csc函数(csc函数值)
  17. 学生专用计算机怎样开启关机,怎么设置电脑自动关机?
  18. NULL 指针在不同平台下的表现引发程序报错(C 语言)
  19. [css3] 小案例-扇子
  20. gazebo仿真rotors调整实时比例的方法

热门文章

  1. 用计算机画画教学设计,黔教版信息技术四年级上册第2课《用计算机的“笔”来画画》教案1.doc...
  2. 使用jQuery封装翻页器
  3. OpenGL(十七)Photoshop blend算法 与 图层混合模式
  4. 一文带你深刻的进入python,并且了解python的优缺点
  5. win10下执行Hadoop命令报错:系统找不到指定的路径。Error: JAVA_HOME is incorrectly set. Please update D:\
  6. 在SpringBoot中启动时关于连接数据库失败的问题
  7. 华为鸿蒙手表mate watch,鸿蒙要上手表?Mate Watch或将与Mate 40同时推出
  8. 移动端和PC端的录屏软件汇总,需要的朋友速看
  9. Java SE进阶知识
  10. 面试失败十次是一种什么样的体验?