fix: 设计模式添加

This commit is contained in:
haishan 2021-11-22 13:24:19 +08:00
parent 642f06dfdf
commit 79143a69eb
3 changed files with 214 additions and 140 deletions

69
docs/fea/js/index.md Normal file
View File

@ -0,0 +1,69 @@
---
nav:
title: 前端
path: /fea
group:
title: 💊 JavaScript
order: 2
path: /js
---
# 💊 JavaScript
## 深拷贝 VS 浅拷贝
> 区别:浅拷贝只拷贝一层,深拷贝无限层级拷贝
### 浅拷贝(方案 1
遍历
```js
function shallowClone(source) {
var target = {};
for (var i in source) {
if (source.hasOwnProperty(i)) {
target[i] = source[i];
}
}
return target;
}
```
### 深拷贝(方案 1
遍历 + 递归
**该方法出现的问题是:爆栈。当层级太深的时候会发生**
```js
function isObject(x) {
return Object.prototype.toString.call(x) === '[object Object]';
}
function deepClone(source) {
if (!isObject(source)) return source;
var target = {};
for (var i in source) {
if (source.hasOwnProperty(i)) {
if (typeof source[i] === 'object') {
target[i] = deepClone(source[i]); // 注意这里
} else {
target[i] = source[i];
}
}
}
return target;
}
```
### 深拷贝(方案 2
```js
function cloneJSON(source) {
return JSON.parse(JSON.stringify(source));
}
```

View File

@ -9,56 +9,65 @@ group:
## 关于
学习设计模式,是为了让你的代码减少亢余,能用健壮的代码去解决问题,提升可维护性与拓展性。
**想做靠谱开发,先学设计模式**
### 最终目标
1. 充分理解前端设计模式的核心思想和基本理念,在具体的场景中掌握抽象的设计原则
2. 会写代码,会写好代码
3. 会面试,能言之有物
## SOLID 设计原则
设计模式需要遵循五个原则,被称为 SOLID 原则,内容分别是:
设计模式需要遵循五个原则被称为SOLID原则内容分别是
- 单一功能原则Single Responsibility Principle【_重点_】
- 开放封闭原则Opened Closed Principle【_重点_】
- 里式替换原则Liskov Substitution Principle
- 接口隔离原则Interface Segregation Principle
- 依赖反转原则Dependency Inversion Principle
* 单一功能原则Single Responsibility Principle
* 开放封闭原则Opened Closed Principle
* 里式替换原则Liskov Substitution Principle
* 接口隔离原则Interface Segregation Principle
* 依赖反转原则Dependency Inversion Principle
> 将变与不变分离,确保变化的部分灵活,不变的部分稳定。
> "SOLID" 是由罗伯特·C·马丁在 21 世纪早期引入的记忆术首字母缩略字,指代了面向对象编程和面向对象设计的五个基本原则。
## 设计模式分类早期22种新增1种
## 设计模式分类(早期 22 种,新增 1 种)
### 创建型
创建型模式封装了创建对象过程中的变化,它做的事情就是将创建对象的过程抽离;
* 单例模式
* 原型模式
* 构造器模式
* 工厂模式
* 抽象工厂模式
* 建造者(新)
- 单例模式
- 原型模式
- 构造器模式
- 工厂模式
- 抽象工厂模式
- 建造者(新)
### 结构型
结构型模式封装的是对象之间组合方式的变化,目的在于灵活地表达对象间的配合与依赖关系;
* 桥接模式
* 外观模式
* 组合模式
* 装饰器模式
* 适配器模式
* 代理模式
* 享元模式
- 桥接模式
- 外观模式
- 组合模式
- 装饰器模式
- 适配器模式
- 代理模式
- 享元模式
### 行为型
而行为型模式则将是对象千变万化的行为进行抽离,确保我们能够更安全、更方便地对行为进行更改
* 迭代器模式
* 解释器模式
* 观察者模式
* 中介者模式
* 访问者模式
* 状态模式
* 备忘录模式
* 策略模式
* 模板方法模式
* 职责链模式
* 命令模式
- 迭代器模式
- 解释器模式
- 观察者模式
- 中介者模式
- 访问者模式
- 状态模式
- 备忘录模式
- 策略模式
- 模板方法模式
- 职责链模式
- 命令模式

View File

@ -17,40 +17,40 @@ group:
#### 简单版
场景是我需要创建500个用户他们分别有不同的角色页面访问不同权限。
场景是我需要创建 500 个用户,他们分别有不同的角色,页面访问不同权限。
```js
class User {
constructor(name, type, viewPage) {
this.type = type
this.name = name
this.viewPage = viewPage
}
class User {
constructor(name, type, viewPage) {
this.type = type;
this.name = name;
this.viewPage = viewPage;
}
}
export default function getUserTypeFactory(name, type) {
let viewPage
switch (type) {
case 'superAdmin':
viewPage = ['首页', '通讯录', '发现页', '应用数据', '权限管理']
break;
case 'admin':
viewPage = ['首页', '通讯录', '发现页', '应用数据']
break;
case 'normal':
viewPage = ['首页', '通讯录', '发现页']
break;
default:
throw new Error('参数错误可选参数superAdmin、admin、normal')
}
let viewPage;
switch (type) {
case 'superAdmin':
viewPage = ['首页', '通讯录', '发现页', '应用数据', '权限管理'];
break;
case 'admin':
viewPage = ['首页', '通讯录', '发现页', '应用数据'];
break;
case 'normal':
viewPage = ['首页', '通讯录', '发现页'];
break;
default:
throw new Error('参数错误可选参数superAdmin、admin、normal');
}
return new User(name, type, viewPage)
return new User(name, type, viewPage);
}
```
### 抽象工厂模式
结合上文中的工厂,发现它不完全遵循 **SOLID法则** 中的开放封闭原则:对拓展开放,对修改封闭。
结合上文中的工厂,发现它不完全遵循 **SOLID 法则** 中的开放封闭原则:对拓展开放,对修改封闭。
这篇文章我用一个手机从出产到上市使用的一个创建过程,首先我们知道,手机由两部分组成 **软件** **硬件**
@ -59,12 +59,12 @@ export default function getUserTypeFactory(name, type) {
class AbstractFactory {
// 操作系统接口
createOS() {
throw new Error('抽象方法不允许直接调用,你需要将我重写')
throw new Error('抽象方法不允许直接调用,你需要将我重写');
}
// 提供硬件接口
createHardWare() {
throw new Error('抽象方法不允许直接调用,你需要将我重写')
throw new Error('抽象方法不允许直接调用,你需要将我重写');
}
}
@ -73,34 +73,34 @@ class FakeStarFactory extends AbstractFactory {
// 操作系统接口
createOS() {
// 安卓系统实例
return new AndroidOS()
return new AndroidOS();
}
// 提供硬件接口
createHardWare() {
// 高通硬件实例
return new QualcommHardWare()
return new QualcommHardWare();
}
}
// 2-1. 抽象产品(软件):只定义
class OS {
controlHardWare() {
throw new Error('抽象方法不允许直接调用,你需要将我重写')
throw new Error('抽象方法不允许直接调用,你需要将我重写');
}
}
// 2-2. 具体产品:安卓操作系统
class AndroidOS extends OS {
controlHardWare() {
console.log('我会用安卓的方法去运行操作系统')
console.log('我会用安卓的方法去运行操作系统');
}
}
// 2-2. 具体产品:苹果操作系统
class AppleOS extends OS {
controlHardWare() {
console.log('我会用苹果的方法去运行操作系统')
console.log('我会用苹果的方法去运行操作系统');
}
}
@ -108,21 +108,21 @@ class AppleOS extends OS {
class HardWare {
// 手机硬件的共性方法:根据命令运转
operateByOrder() {
throw new Error('抽象方法不允许直接调用,你需要将我重写')
throw new Error('抽象方法不允许直接调用,你需要将我重写');
}
}
// 3-2. 具体产品(硬件):高通
class QualcommHardWare extends HardWare {
operateByOrder() {
console.log('我会用高通的方式去运转')
console.log('我会用高通的方式去运转');
}
}
// 3-2. 具体产品(硬件):英特尔
class InterHardWare extends HardWare {
operateByOrder() {
console.log('我会用英特尔的方式去运转')
console.log('我会用英特尔的方式去运转');
}
}
@ -134,22 +134,20 @@ const myOS = myMobile.createOS();
const myHardWare = myOS.createHardWare();
// 启动操作系统
myOS.controlHardWare()
myOS.controlHardWare();
// 唤醒硬件命令
myHardWare.operateByOrder()
myHardWare.operateByOrder();
```
以上就是我们通过场景创建的四个重要的角色:
* 抽象工厂(抽象类,它不能被用于生成具体实例): 用于声明最终目标产品的共性。在一个系统里,抽象工厂可以有多个(大家可以想象我们的手机厂后来被一个更大的厂收购了,这个厂里除了手机抽象类,还有平板、游戏机抽象类等等),每一个抽象工厂对应的这一类的产品,被称为“产品族”。
* 具体工厂(用于生成产品族里的一个具体的产品): 继承自抽象工厂、实现了抽象工厂里声明的那些方法,用于创建具体的产品的类。
* 抽象产品(抽象类,它不能被用于生成具体实例): 上面我们看到,具体工厂里实现的接口,会依赖一些类,这些类对应到各种各样的具体的细粒度产品(比如操作系统、硬件等),这些具体产品类的共性各自抽离,便对应到了各自的抽象产品类。
* 具体产品(用于生成产品族里的一个具体的产品所依赖的更细粒度的产品): 比如我们上文中具体的一种操作系统、或具体的一种硬件等。
总结下来,抽象工厂就类似 typescript 里面的 interface 申明对象。
- 抽象工厂(抽象类,它不能被用于生成具体实例): 用于声明最终目标产品的共性。在一个系统里,抽象工厂可以有多个(大家可以想象我们的手机厂后来被一个更大的厂收购了,这个厂里除了手机抽象类,还有平板、游戏机抽象类等等),每一个抽象工厂对应的这一类的产品,被称为“产品族”。
- 具体工厂(用于生成产品族里的一个具体的产品): 继承自抽象工厂、实现了抽象工厂里声明的那些方法,用于创建具体的产品的类。
- 抽象产品(抽象类,它不能被用于生成具体实例): 上面我们看到,具体工厂里实现的接口,会依赖一些类,这些类对应到各种各样的具体的细粒度产品(比如操作系统、硬件等),这些具体产品类的共性各自抽离,便对应到了各自的抽象产品类。
- 具体产品(用于生成产品族里的一个具体的产品所依赖的更细粒度的产品): 比如我们上文中具体的一种操作系统、或具体的一种硬件等。
总结下来,抽象工厂就类似 typescript 里面的 interface 申明对象,使用工厂模式的目的,就是为了实现**无脑传参**,就是为了爽!
### 单例模式
@ -160,22 +158,22 @@ myHardWare.operateByOrder()
```js
// ------------------- 单例模式 -------------------
export default class Singleton {
show() {
console.log('我是一个单例对象')
}
show() {
console.log('我是一个单例对象');
}
static getInstance() {
if (!this.instance) {
this.instance = new Singleton()
}
return this.instance
static getInstance() {
if (!this.instance) {
this.instance = new Singleton();
}
return this.instance;
}
}
const s1 = Singleton.getInstance()
const s2 = Singleton.getInstance()
const s1 = Singleton.getInstance();
const s2 = Singleton.getInstance();
s1 === s2 // => true
s1 === s2; // => true
```
#### 进阶版
@ -185,25 +183,24 @@ s1 === s2 // => true
```js
class Storage {
constructor() {
this.instance = null
this.instance = null;
}
static getInstance() {
if (!this.instance) {
this.instance = new Storage()
this.instance = new Storage();
}
return this.instance
return this.instance;
}
getItem(key) {
return localStorage.getItem(key)
return localStorage.getItem(key);
}
setItem(key, value) {
return localStorage.setItem(key, value)
return localStorage.setItem(key, value);
}
}
```
### 构造器模式
@ -214,16 +211,16 @@ class Storage {
// 一个构造函数
class Asshole {
constructor(name, age) {
this.name = name
this.age = age
this.name = name;
this.age = age;
}
say() {
console.log(`I'm asshole ${this.name},${this.age} years old.`)
console.log(`I'm asshole ${this.name},${this.age} years old.`);
}
}
const me = new Asshole('json', 28)
const me = new Asshole('json', 28);
```
**谈原型模式,其实是谈原型范式**,原型编程范式的核心思想就是利用实例来描述对象,用实例作为定义对象和继承的基础。在 JavaScript 中,原型编程范式的体现就是基于原型链的继承。这其中,对 **原型、原型链** 的理解是关键。
@ -235,26 +232,25 @@ const me = new Asshole('json', 28)
```ts
const deepClone = (obj) => {
// 如果是值类型或者不存在,直接返回
if (typeof obj !== 'object' || obj === null) return obj
if (typeof obj !== 'object' || obj === null) return obj;
// 定义结果对象
let copy = {}
let copy = {};
// 如果对象是数组,则定义结果数组
if (obj.constructor === Array) copy = []
if (obj.constructor === Array) copy = [];
// 遍历对象的 key
for (let key in obj) {
// 如果key是对象的自身属性
if (obj.hasOwnProperty(key)) {
// 递归调用深拷贝方法
copy[key] = deepClone(obj[key])
}
}
return copy
}
// 遍历对象的 key
for (let key in obj) {
// 如果key是对象的自身属性
if (obj.hasOwnProperty(key)) {
// 递归调用深拷贝方法
copy[key] = deepClone(obj[key]);
}
}
return copy;
};
```
### 建造者模式
@ -262,40 +258,40 @@ const deepClone = (obj) => {
```js
// 建造者模式 需要优化
export default class Builder {
constructor() {
this.name = ''
this.author = ''
this.price = 0
this.category = ''
}
constructor() {
this.name = '';
this.author = '';
this.price = 0;
this.category = '';
}
withName(name) {
this.name = name
return this
}
withName(name) {
this.name = name;
return this;
}
withAuthor(author) {
this.author = author
return this
}
withAuthor(author) {
this.author = author;
return this;
}
withPrice(price) {
this.price = price
return this
}
withPrice(price) {
this.price = price;
return this;
}
withCategory(category) {
this.category = category
return this
}
withCategory(category) {
this.category = category;
return this;
}
build() {
return {
name: this.name,
author: this.author,
price: this.price,
category: this.category
}
}
build() {
return {
name: this.name,
author: this.author,
price: this.price,
category: this.category,
};
}
}
```