最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

【当前独家】JavaScript设计模式

来源:博客园

JavaScript设计模式

设计模式概念

经过代码设计经验总结之后设计出的一种固定解决问题的方式

设计模式作用

  • 代码复用


    (资料图片仅供参考)

  • 保证代码可靠性

  • 将编程工程化

  • 更易被他人理解

设计模式的分类(W3C平台)

构造器模式,模块化模式,暴露模块模式,单例模式,中介者模式,原型模式,命令模式,外观模式,工厂模式,Mixin模式,装饰模式,亨元(Flyweight)模式,MVC模式,MVP模式,MVVM模式,组合模式,适配器模式,外观模式,观察者模式,迭代器模式,惰性初始模式,代理模式,建造者模式,...

常用设计模式

1. 单例模式

概念 :

多次操作是在同一个实例对象上实现 即第一次为创建实例对象 后面的都是在原有的实例对象上操作

优点 :

节省性能 提升执行速度

function Fn(){      // 这里自定义__obj__是为了防止和Fn内置对象名重叠      if(!Fn.__obj__){          // 这里没有这个对象存在再创建 有则不创建          // 保证单例的核心          Fn.__obj__ = {};      }      Fn.__obj__.name = "admin";      return Fn.__obj__;  }

2. 工厂模式

概念 :

多次创建多个具有相同属性名相同方法功能的不同实例对象

工厂模式的标志 :

原料(创建基础对象) 加工(给基础对象添加属性或方法) 出厂(将基础对象返回到外部)

优点 :

相互独立 分别控制 互不干扰

function Fn(name, age){    this.name = name;    this.age = age  }  const f1 = new Fn("admin", 18)  const f2 = new Fn("root", 19)  // 工厂模式和单例模式不同 每次创建的都是新实例对象  console.log(f1 === f2);  // false

3. 抽象工厂模式

概念 :

在工厂模式的基础上进行二次封装,将相同的属性值再次封装

// 造车厂  function CreateCar(brand, color, type){    this.brand = brand;    this.color = color;    this.type = type;  }  // 专门用来生产比亚迪的生产线  function BYDCar(color, type){    return new CreateCar("比亚迪", color, type);  }  const b1 = new BYDCar("白色", "SUV");  const b2 = new BYDCar("红色", "轿车");  // 专门用来生产大众的生产线  function WCar(color, type){    return new CreateCar("大众", color, type);  }  const w1 = new WCar("黑色", "SUV");  const w2 = new WCar("灰色", "轿车");

4. 适配器模式

概念 :

解决两个软件实体间的接口不兼容的问题,对不兼容的部分进行适配

例 : 手机没有3.5耳机插口,所以就需要增加一个转接头来完成适配功能以确保耳机的正常使用

// 创建一个手机构造器 有打电话打游戏功能  function CreatePhone(){    this.name = "手机"    this.call = function(){      console.log("打电话")    }    this.game = function(){      console.log("玩游戏")    }  }  // 创建一个电脑构造器 有游戏功能  function CreateComputer(){    this.name = "电脑"    this.game = function(){      console.log("玩游戏")    }  }  // 测试打电话和游戏功能  function test(obj){    obj.call();    obj.game();  }  const p = new CreatePhone()  const c = new CreateComputer()  // 如果没有适配器 电脑因为没有打电话功能test会报错  function Adapter(obj){    // 如果没有这个功能则定义一个这个功能    if(!obj.call){      obj.call = function(){        console.log("这是" + obj.name + "没有打电话功能")      }    }    return obj;  }  test(p);  // 打电话  // 玩游戏  test( Adapter(c) );  // 这是电脑没有打电话功能  // 玩游戏  console.log(p)  console.log(c)

5. 代理模式

概念

不直接访问对象 而是提供一个中间对象(代理)来控制对这个对象的访问

生活中也有比较常见的代理模式:中介、寄卖、经纪人等等

// 发送数据方 target为接收方 name为发送方名字  function sender(target, name){    this.name = name;    // 定义发送方式    this.send = function(msg){      console.log(this.name + "将" + msg + "交给了" + target.name);    }  }  // 接收数据方 name为接收方名字  function reciver(name){    this.name = name;  }  // 创建"bob"实例对象用于接收数据  const s = new reciver("bob");  // 定义中间代理 target为接收方  function poster(target){    // 创建发送方实例对象    const f = new sender(s, "tom");    //message用于存储各种数据    this.message = [];    this.send = function(msg){      this.message.push({        发件人: f.name,        收件人: target.name,        物品: msg,        时间: Date.now()      })      //调用发送方send方法 msg为传进来参数      f.send(msg);    }  }  // 创建代理实例对象  const k = new poster(s);  // 代理发送方tom发送数据给接收方bob  k.send("一批教材");  k.send("一批教具");  k.send("一批学生");  console.log(k.message);

6. 观察者模式

又称发布订阅模式(Publish/Subscribe)

概念

观察者模式定义了一种一对多的关系 让一个对象(发布者Dep)能被多个观察者(订阅者Observer)同时监听

优点

  • 支持简单的广播通信 自动通知所有订阅者
  • 页面载入后发布者很容易与观察者存在一种动态关联 增加了灵活性
  • 发布者与观察者之间的抽象耦合关系能够单独扩展以及重用(解耦)
function MyEvent() {    // 定义一个对象存储dep和数组形式的observer    this.message = {};    // 绑定发布者和目标订阅者    this.binding = function(dep, observer) {      if (this.message[dep]) {        // 发布者存在 则加入新的订阅者        this.message[dep].push(observer);      } else {        // 发布者不存在 则创建一个数组 存入第一个订阅者        this.message[dep] = [observer];      }    }    // 绑定发布者和目标订阅者    this.unbinding = function(dep, observer) {      // 发布者不存在 则返回      if (!this.message[dep]) return;      // 找到订阅者在数组中的索引      var index = this.message[dep].indexOf(observer);      if (index != -1) {        // 如果有 则从索引位置删除他        this.message[dep].splice(index, 1);      }    }        // 执行目标发布者的所有订阅者的行为    this.emit = function(dep) {      // 发布者不存在 则返回      if (!this.message[dep]) return;      // 调用所有订阅者方法      this.message[dep].forEach((val) => {val(dep);})    }  }  // 创建实例对象  const event = new MyEvent();  // 绑定发布者和订阅者  event.binding("bob", follower1);  event.binding("bob", follower2);  event.binding("tom", follower1);  event.binding("tom", follower2);  // 解绑发布者和目标订阅者  event.unbinding("tom", follower1);  // 执行目标发布者所有订阅者行为  event.emit("bob");  event.emit("tom");  // 定义订阅者行为  function follower1(dep) {    console.log("follower1订阅了" + dep)  }  function follower2(dep) {    console.log("follower2我订阅了" + dep)  }

7. 策略模式

概念 :

将多个功能封装起来 定义一系列算法 并使他们能直接相互替换

优点 :

  • 利用组合 委托 避免了条件语句
  • 使代码更易理解和扩展
  • 代码复用
// 需求: 绩效计算  // 条件选择方式 if分支随着绩效分类增多而增多 影响性能  let bonus = function (performance, salary) {    if(performance == "S") {      return salary * 4;    } else if (performance == "A") {      return salary * 3;    } else if (performance == "B")      return salary * 2;  }  // 策略模式    let calculateBonus = {    "S": function ( salary ){      return salary * 4;    },    "A": function ( salary ) {      return salary * 3;    },    "B": function ( salary ) {       return salary * 2;    }  }  function calculate(level, salary) {    return calculateBonus[level](salary);  }  console.log(calculate("S", 20000) + "$")

8. MVC模式

全名: Model View Controller 模型 视图 控制器

  • M: 模型 按照要求来取出数据
  • V: 视图 用户直观看到的页面
  • C: 控制器 向系统发出指令的工具

优点

  • 降低代码耦合
  • 分工合作 提高开发效率
  • 组件重用

工作流程

  1. 用户的请求提交给控制器

  2. 控制器接收到用户请求后根据用户的具体需求 调用相应的程序来处理用户的请求

  3. 控制器调用程序处理完数据后 将数据显示出来

// 定义模型 按照要求读取数据  class Model {    m1() {      return "Model1";    }    m2() {      return "Model2";    }  }  // 定义视图 用于数据展示  class View {    v1(m) {      console.log(m);    }    v2(m) {      document.write(m);    }  }  // 根据控制器找到对应数据  class Control {    constructor() {      this.m = new Model();      this.v = new View();    }    c1() {      let value = this.m.m1();      this.v.v1(value);    }    c2() {      let value = this.m.m2();      this.v.v2(value);    }  }  // 创建一个控制器实例对象  const c = new Control();  // 发出指令  c.c1();  c.c2();

9. 组合模式

概念 :

把多个对象组成树状结构来表示局部与整体,使得用户可以同时操作单个对象或对象的组合

优点 :

  • 组合模式可以非常方便地描述对象部分-整体层次结构
  • 组合模式将一批子对象组织为树形结构 一条根命令能操作下面所有子元素
//   // 枝  class Team {    constructor(id) {      // 组合模式核心之一 使得每个元素都能保存自己所有的子元素      this.children = [];      this.ele = document.createElement("div");      this.ele.id = id;    }      add(child) {      // 在数组中加入child元素      this.children.push(child);      // 将child添加到当前实例对象对应元素(this.ele)中      this.ele.appendChild(child.ele);    }    remove(child) {      // 找到这个child元素在数组中索引      let c = this.children.indexOf(child);      // 根据索引删除元素      this.children.splice(c, 1);      // child为实例对象 找到实例对象对应元素 并删除节点元素      child.ele.remove();    }    addBorder() {      // 给当前实例对象对应元素添加边框      this.ele.style.border = "2px solid black";      // 以下递归和核心之一      // 给当前实例对象children数组(保存所有子元素对应实例对象)中所有元素也添加边框 如果子实例对象对应实例对象中还有实例对象则递归进去 重复之前步骤 直到所有子孙元素      this.children.forEach(val => {val.addBorder()});    }    removeBorder() {      // 给当前实例对象对应元素删除边框      this.ele.style.border = "none";      // 原理同addBorder      this.children.forEach(val => {val.removeBorder()});    }  }  // 叶  class Item {    constructor(src) {      // 此处ele为核心之一 这里的ele必须和上面枝中的ele相同 如果不同 this.ele在递归到叶中实例对象时 因找不到ele元素而报错而报错      this.ele = document.createElement("img");      this.ele.src = src;    }    add() {      console.log("此为叶节点 不能添加");    }    remove() {      console.log("此为叶节点 不能删除");    }    addBorder() {      // 叶没有子元素 所以只要给自己添加边框      this.ele.style.border = "2px solid red";    }    removeBorder() {      // 叶没有子元素 所以只要给自己删除边框      this.ele.style.border = "none";    }  }  // 创建叶实例对象  const img1 = new Item("https://t7.baidu.com/it/u=1595072465,3644073269&fm=193&f=GIF");  const img2 = new Item("https://t7.baidu.com/it/u=4198287529,2774471735&fm=193&f=GIF");  const img3 = new Item("https://t7.baidu.com/it/u=2511982910,2454873241&fm=193&f=GIF");  const img4 = new Item("https://t7.baidu.com/it/u=3435942975,1552946865&fm=193&f=GIF");  // 创建枝对象  const box1 = new Team("box1");  const box2 = new Team("box2");  const box3 = new Team("box3");  const box4 = new Team("box4");  const box5 = new Team("box5");  // 将盒子 和 img组合  box1.add(box2);  box1.add(box3);  box3.add(box4);  box4.add(box5);  box1.add(img1);  box4.add(img2);  box4.add(img3);  box5.add(img3);  // 以下为box在body中排列    //   box1    //     box2    //     box3    //       box4    //         box5              // img3          //   img2          //   img3          // img1  // 将根box1添加到body中  document.body.appendChild(box1.ele);  // 给元素添加删除边框  box1.addBorder();  box3.addBorder();  img2.removeBorder();

关键词: