常见 JavaScript 设计模式 — 原来这么简单(二)

简介: 常见 JavaScript 设计模式 — 原来这么简单

结构型设计模式

装饰器模式

核心是在不改变原 对象/方法 的基础上,通过对其进行包装拓展,使原有 对象/方法 可以满足更复杂的需求.

装饰器本质

装饰器模式本质上就是 函数的传参和调用,通过函数为已有 对象/方法 进行扩展,而不用修改原对象/方法,满足 开放封闭原则.

通过配置 babel 通过将 test.js 转为为 bable_test.js 用来查看装饰器的本质:

babel.config.json

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": "current"
        }
      }
    ]
  ],
  "plugins": [
    ["@babel/plugin-proposal-decorators", { "legacy": true }],
    ["@babel/plugin-proposal-class-properties", { "loose": true }]
  ]
}
复制代码

test.js

// 定义装饰器
function decoratorTest(target) {
  console.log(target);
}
// 使用装饰器,装饰 Person 类
@decoratorTest
class Person {
  say() {}
  eat() {}
}
复制代码

执行 babel test.js --out-file babel_test.js 命令是生成 babel_test.js

"use strict";
var _class;
function decoratorTest(target) {
  console.log(target);
}
let Person = decoratorTest(_class = class Person {
  say() {}
  eat() {}
}) || _class;
复制代码

React 中的装饰器模式 —— HOC 高阶组件

高阶组件 是参数为 组件,返回值为新组件的 函数,在 ReactHOC 通常用于复用组件公共逻辑.

// TodoList 组件
class TodoList extends React.Component {}
// HOC 函数
function WrapContainer(Comp) {
  return (
    <div style={{ border: "1px solid red", padding: 10 }}>
      <Comp title="todo" />
    </div>
  );
}
// HOC 装饰 TodoList 组件,为 TodoList 组件包裹红色边框
const newTodoList = WrapContainer(TodoList);
复制代码

适配器模式

适配器模式本质就是 让原本不兼容的功能能够生效,避免大规模修改代码,对外提供统一使用.

Axios 中的适配器

通过观察 Axios 的目录结构,很容就发现其使用了适配器模式:

image.png

其实 Axios 中的 adapters 主要目的是根据当前运行时环境,向外返回对应的适配器 adapter,而这个适配器要做的其实就是兼容 web 浏览器环境和 node 环境的 http 请求,保证对外暴露的仍然是统一的 API 接口

代理模式

代理模式顾名思义就是 不能直接访问目标对象,需要通过代理器来实现访问,通常是为了提升性能、保证安全等.

事件代理

事件代理是很常见的性能优化手段之一,react 的事件机制也采用了事件代理的方式(篇幅有限可自行了解),这里演示简单的 JavaScript 事件代理:

<div id="container">
  <p>this number is 1</p>
  <p>this number is 2</p>
  <p>this number is 3</p>
  <p>this number is 4</p>
  <p>this number is 5</p>
</div>
<script>
  const container = document.querySelector("#container");
  container.addEventListener("click", function (e) {
    alert(e.target.textContent);
  });
</script>
复制代码

Vue 中的代理 Proxy

Vue.js 3 中通过 Proxy 实现了对数据的代理,任何读取、设置的操作都会被 代理对象handlers 拦截到,从而实现 Vue 中的 tracktrigger

image.png

image.png

行为型设计模式

策略模式

策略模式实际上就是定义一系列的算法,将单个功能封装起来,并且对扩展开放.

举个例子

假如我们需要为某个游乐场的门票价格做差异化询价,主要人员类型分为 儿童、成年人、老年人 三种,其对应的门票折扣为 8折、9折、8.5折

if-else 代码一把梭

缺点:无论哪种人员类型的折扣变动,都需要修改 finalPrice 函数,不符合对 对修改封闭

function finalPrice(type, price) {
  if (type === "child") {
    // do other thing
    return price * 0.8;
  }
  if (type === "adult") {
    // do other thing
    return price * 0.9;
  }
  if (type === "aged") {
    // do other thing
    return price * 0.85;
  }
}
复制代码

单一功能封装

缺点:若人员类型增加妇女类型,仍然需要修改 finalPrice 函数,且不符合 对扩展开放

function childPrice(price) {
  // do other thing
  return price * 0.8;
}
function adultPrice(price) {
  // do other thing
  return price * 0.9;
}
function agedPrice(price) {
  // do other thing
  return price * 0.85;
}
function finalPrice(type, price) {
  if (type === "child") {
    return childPrice(price);
  }
  if (type === "adult") {
    return adultPrice(price);
  }
  if (type === "aged") {
    return agedPrice(price);
  }
}
复制代码

创建映射关系

通过映射关系,很好的将 finalPrice 和 具体的计算逻辑进行分离,在需要扩展类型时,只需要修改 priceTypeMap 对象而不用修改对外暴露的 finalPrice 函数.

const priceTypeMap = {
  child: function (price) {
    // do other thing
    return price * 0.8;
  },
  adult: function (price) {
    // do other thing
    return price * 0.9;
  },
  aged: function (price) {
    // do other thing
    return price * 0.85;
  },
};
function finalPrice(type, price) {
    return priceTypeMap[type](price);
}


目录
相关文章
|
11天前
|
设计模式 前端开发 JavaScript
【JavaScript 技术专栏】JavaScript 设计模式与实战应用
【4月更文挑战第30天】本文探讨JavaScript设计模式在提升开发效率和代码质量中的关键作用。涵盖单例、工厂、观察者、装饰器和策略模式,并通过实例阐述其在全局状态管理、复杂对象创建、实时数据更新、功能扩展和算法切换的应用。理解并运用这些模式能帮助开发者应对复杂项目,提升前端开发能力。
|
5月前
|
设计模式 JavaScript 数据安全/隐私保护
js设计模式之工厂模式
js设计模式之工厂模式
34 0
|
4月前
|
设计模式 前端开发 算法
【面试题】 ES6 类聊 JavaScript 设计模式之行为型模式(二)
【面试题】 ES6 类聊 JavaScript 设计模式之行为型模式(二)
|
2月前
|
设计模式 缓存 JavaScript
js常用设计模式
js常用设计模式
22 1
|
5月前
|
设计模式 存储 JavaScript
js设计模式之单例模式
js设计模式之单例模式
47 7
|
10月前
|
设计模式 前端开发 JavaScript
|
10月前
|
设计模式 前端开发 JavaScript
|
7月前
|
设计模式 JSON 前端开发
前端面试必看(手写Promise+js设计模式+继承+函数柯里化等)JavaScript面试全通关(1/3)
前端面试必看(手写Promise+js设计模式+继承+函数柯里化等)JavaScript面试全通关(1/3)
43 0
|
8月前
|
设计模式
js-设计模式
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类的、代码设计经验的总结。
|
10月前
|
存储 设计模式 前端开发