读书笔记:前端开发的变与不变 —— JavaScript设计模式

177 阅读3分钟

前言

前端在大多数人眼中的理解就是html+css+js,前端框架层出不穷,前端业务也越来越复杂。用健壮的代码来满足复杂的需求变得尤为重要。健壮的代码于我而言,就是变化的好扩展,不变的很稳定。这让我想到了设计模式的SO原则。

每日一学之设计模式

2020.4.1 工厂模式(简单) —— 变与不变(无脑传参)

  • 工厂模式就是将创建对象的过程封装起来。
  • 通俗的说,就好比你去餐馆吃一顿饭,你点了番茄炒蛋,你不需要关心上菜之前厨师和上菜服务员的任何操作。你只需要关注点菜这个动作。
const map = {
	coder: ['code', 'learn'],
	UI: ['design']
}
function User(name, age, job, work){
	this.name = name;
	this.age = age;
	this.job = job;
	this.work = work;
}

function Factory(name, age, job){
	const work = map[job];
	return new User(name, age, job, work);
}

2020.4.1 工厂模式(抽象)—— 围绕一个超级工厂创建其他工厂

// 抽象工厂
class MobilePhoneFactory{
	createOs(){
		throw new Error('抽象方法不能直接调用,你需要将我重写!')
	}
	createHardWare(){
		throw new Error('抽象方法不能直接调用,你需要将我重写')
	}
}

// 具体工厂继承抽象工厂
class FakeStarFactory extends MobilePhoneFactory{
	createOs(){
		// 提供安卓系统实例
		return new AndroidOs();
	}
	createHardWare(){
		// 提供高通硬件实例
		return new QualcommHardWare();
	}
}

// 抽象操作系统产品类
class Os{
	controlHardWare(){
		throw new Error('抽象产品类不能直接调用,你需要将我重写')
	}
}

// 定义具体的产品类
class AndroidOs extends Os{
	controlHardWare(){
		console.log('我会用安卓的方式去操作硬件')
	}
}

class IosOs extends Os{
	controlHardWare(){
		console.log('我会用的方式去操作硬件')
	}
}

// ...抽象硬件产品类同理,

// 定义手机硬件这类产品的抽象产品类
class HardWare {
	// 手机硬件的共性方法,这里提取了“根据命令运转”这个共性
	operateByOrder() {
		throw new Error('抽象产品方法不允许直接调用,你需要将我重写!');
	}
}

// 定义具体硬件的具体产品类
class QualcommHardWare extends HardWare {
	operateByOrder() {
		console.log('我会用高通的方式去运转')
	}
}

class MiWare extends HardWare {
	operateByOrder() {
		console.log('我会用小米的方式去运转')
	}
}

// 所以你生产一部手机就只需要

const myPhone = new FakeStarFactory(); // new一个手机
const myOs = myPhone.createOs(); // 让它拥有系统
const myHardWare = myPhone.createHardWare(); // 让它拥有硬件
myOs.controlHardWare(); // 启动操作系统,系统去操作硬件
myHardWare.operateByOrder(); // 唤醒硬件

2020.4.7 单例模式 —— 一个实例,全局访问

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

class Single {
  show() {
    console.log("zzz");
  }
  static getInstance() {
    if (!Single.instance) {
			Single.instance = new Single();
		}
		return Single.instance
  }
}

const s1 = Single.getInstance()
const s2 = Single.getInstance()

s1 === s2  // true

2020.4.9 原型模式 —— 用实例来描述对象,用实例作为定义对象和继承的基础

构造函数、构造函数的原型对象和实例对象三个实体之间的关系。 构造函数有prototype属性指向原型对象,原型对象的constructor属性指向构造函数,通过构造函数new的实例对象有_proto_属性指向原型对象。

原型链:

注意关联:对象的深拷贝

2020.4.9 装饰器模式 —— 只添加不修改

function classDecorator(target){
    target.hasDecorator = true;
    return target;
}

@classDecorator
class Button{

}

console.log('Button 是否被装饰了:', Button.hasDecorator)
// babel转码之后:

'use strict';

var _class;

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function classDecorator(target) {
    target.hasDecorator = true;
    return target;
}

var Button = classDecorator(_class = function Button() {
    _classCallCheck(this, Button);
}) || _class;

console.log('Button 是否被装饰了:', Button.hasDecorator);

注意关联:高阶组件

2020.4.14 适配器模式 —— iphoneX的方形耳机孔使用圆形耳机

把变化留给自己,把统一留给用户。统一的入参,统一的出参,统一的规则。

注意关联: axios中的适配器

2020.4.15 代理模式 —— kexue上网

一个对象不能直接访问另一个对象,需要第三者牵线搭桥,实现访问的目的。这个过程就是代理模式。

  • 事件代理 —— 比如一个div下面的多个子元素添加点击事件
// 获取父元素
const father = document.getElementById('father')

// 给父元素安装一次监听函数
father.addEventListener('click', function(e) {
    // 识别是否是目标子元素
    if(e.target.tagName === 'A') {
        // 以下是监听函数的函数体
        e.preventDefault()
        alert(`我是${e.target.innerText}`)
    }
} )

2020.4.16 策略模式 —— 拒绝if/else,拆分胖逻辑。

未完待续....