前言
本篇主要是读 《JavaScript 设计模式核⼼原理与应⽤实践》的笔记记录。
《JavaScript 设计模式核⼼原理与应⽤实践》的思维导图:
开放封闭原则
软件实体(类、模块、函数)可以扩展,但是不可修改。
JS设计模式
工厂模式·简单工厂
工厂模式其实就是将创建对象的过程单独封装。
例如,软件注册中,让用户选择自己的职业后,新增一个用户
function User(name, email, password, remarks){
this.name = null
this.email = null
this.password = null
// 备注
this.remarks = null
}
function FactoryGetUser(name, email, password, career) {
let remarks
switch(career) {
case 'coder':
remarks = ['技术']
break
case 'product':
remarks = ['产品']
break
case 'xxx':
// 其它工种的备注
...
return new User(name, age, password, remarks)
}
// 调用
let baseUser = FactoryGetUser(null, null, null, "coder")
工厂模式·抽象工厂
这个模式在后端是非常常见的。
在后端其实就是abstract class
,只是es6 js没有这种写法,但是可以曲线救国实现。
例如团队项目内有Axios请求又有ajax请求的(不会真有这样的项目吧...),我们可以将请求封装一下:
// 模拟抽象类
class requestFactory {
// 请求的方法
request(){
throw new Error("抽象工厂方法不允许直接调用,你需要将我重写!");
}
}
// 将Axios请求继承抽象类
class AxiosFactory extends requestFactory {
// 请求的方法
request(url="", method="get", data=null){
// axios(...) balabalabala...
return res;
}
}
// 将ajax请求继承抽象类
class AjaxFactory extends requestFactory {
// 请求的方法
request(url="", method="get", data=null){
// $.ajax balabalabala...
return res;
}
}
/**
* 使用
*/
// 用Axios去请求
let rq = new AxiosFactory();
rq.request("http://xxxx", "post", {});
// 用Ajax去请求
let rq = new AjaxFactory();
rq.request("http://xxxx", "post", {});
这个例子最大的作用大概就是统一了团队内请求调用风格了。
总结:抽象工厂不干活,具体工厂来干活!
单例模式
保证一个类仅有一个实例,并提供一个访问它的全局访问点,这样的模式就叫做单例模式。
众所周知每次new出来的对象都是独立的,但在一些业务场景中我们希望无论在何处new都是最先那个。
比如当前登录用户:
class NowUser {
getUserInfo() {
return {
token: this.token,
name: this.name,
email: this.email,
remarks: this.remarks,
}
}
static getInstance() {
// 判断是否已经new过1个实例
if (!NowUser.instance) {
// 若这个唯一的实例不存在,那么先创建它
NowUser.instance = new NowUser()
}
// 如果这个唯一的实例已经存在,则直接返回
return NowUser.instance
}
}
// 在其它地方中获取当前用户信息
const user1 = NowUser.getInstance()
user1.name="张三"
const user2 = NowUser.getInstance()
user1 === user2 // true
原型模式
原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。
适用于大对象的创建,因为创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需内存拷贝即可。
js深拷贝
function deepClone(obj) {
// 如果是 值类型 或 null,则直接return
if(typeof obj !== 'object' || obj === null) {
return obj
}
// 定义结果对象
let copy = {}
// 如果对象是数组,则定义结果数组
if(obj.constructor === Array) {
copy = []
}
// 遍历对象的key
for(let key in obj) {
// 如果key是对象的自有属性
if(obj.hasOwnProperty(key)) {
// 递归调用深拷贝方法
copy[key] = deepClone(obj[key])
}
}
return copy
}