1. 单例模式 Singleton Pattern
表现形式
let nameSpace = { xxx : xxx };
作用
把描述同一件事务的属性和特征进行”分组,归类”(存储在同一个堆内存中),避免全局变量之间的冲突和污染
高级单例模式
在给命名空间赋值的时候,不是直接赋值一个对象,而是先执行匿名函数,形成一个私有作用域AA(不销毁的栈内存),在AA中创建一个堆内存,把堆内存地址赋值给命名空间 这种模式的好处:我们完全可以在AA中创造很多内容(变量OR函数),哪些需要供外面调取使用的,我们暴露到返回的对象中(模块化实现的一种思想)
let nameSpace = (() => {function f() {}return {f}})();
2. 工厂模式 Factory Pattern
表现形式
let createPerson = (name, age) => ({name, age}); let p1 = createPerson(‘korea’, 20), p2 = createPerson(‘demo’, 21); console.log(p1, p2);
作用
- 1.把实现相同功能的代码进行“封装”,以此来实现“批量生产”(后期想要实现这个功能,我们只需要执行函数即可)
- 2.“低耦合高内聚”:减少页面中的冗余代码,提高代码的重复使用率
- 1.把实现相同功能的代码进行“封装”,以此来实现“批量生产”(后期想要实现这个功能,我们只需要执行函数即可)
3. 构造函数模式 constructor Pattern
表现形式
function Fn(name, age) { let n = 10; this.name = name; this.age = age; } let f = new Fn('kroea', 20);-
4. 原型链设计模式
prototype Pattern 概括
- 原型(prototype)、原型链(proto)
- [函数]
- 普通函数、类(所有的类:内置类、自己创建的类)
- 普通函数、类(所有的类:内置类、自己创建的类)
- [对象]
- 普通对象、数组、正则、Math、arguments…
- 实例是对象类型的(除了基本类型的字面量创建的值)
- prototype的值也是对象类型的
- 函数也是对象类型的
- 普通对象、数组、正则、Math、arguments…
- 原型(prototype)、原型链(proto)
运行机制- 所有的函数数据类型都天生自带一个属性:prototype(原型),这个属性的值是一个对象,浏览器会默认给它开辟一个堆内存
- 在浏览器给prototype开辟的堆内存中有一个天生自带的属性:constructor,这个属性存储的值是当前函数本身
- 每一个对象都有一个
__proto__的属性,这个属性指向当前实例所属类的prototype(如果不能确定它是谁的实例,都是Object的实例)
- 所有的函数数据类型都天生自带一个属性:prototype(原型),这个属性的值是一个对象,浏览器会默认给它开辟一个堆内存
原理图

- 案例
function Fn() {
var n = 100;
this.AA = function () {
console.log(`AA[私]`);
};
this.BB = function () {
console.log(`BB[私]`);
};
}
Fn.prototype.AA = function () {
console.log(`AA[公]`);
};
var f1 = new Fn;
var f2 = new Fn;
console.log(f1.n);
5. 发布订阅模式 Publish subscription mode
- 概念
- 准备一个容器,把到达指定时候要处理的事情,事先一一的增加到容器中(发布计划,并且向计划表中订阅方法), 当到达指定时间点,通知容器中的方法依次执行即可
- 代码实现
~function anonymous(window) {
class Subscribe {
constructor() {
//=>创建一个容器
//每一个实例都有一个自己独有的容器,管理自己需要执行的方法即可
this.pond = [];
}
//=>向计划表(POND池子)中增加方法:去重
//FN:我们需要增加的方法
add(fn) {
let pond = this.pond,
isExist = false;
pond.forEach(item => item === fn ? isExist = true : null);
!isExist ? pond.push(fn) : null;
}
//=>从计划表(POND池子)中移除方法
remove(fn) {
let pond = this.pond;
pond.forEach((item, index) => {
if (item === fn) {
// pond.splice(index, 1);//=>我们不能基于SPLICE删除,因为这种删除方式会改变原有的数组,例如:我们通知方法执行,当执行到FN3的时候(FIRE循环索引是2),但是基于SPLICE把FN1/FN2删除后,原始数组后面的项都向前提取两位,此时FIRE中继续遍历下一个方法(索引3),已经找不到和他匹配的那一项了
//=>让当前项赋值为NULL即可(这样函数移除掉了,但是此时的数组结构没有改变,不会出现数组塌陷的问题)
pond[index] = null;//=>item=null是不行的
}
});
}
//=>通知计划表中的方法依次执行
//如果传递参数信息了,把这些参数依次赋值给执行的每一个方法
fire(...arg) {
let pond = this.pond;
//=>REMOVE机制处理了,此时ITEM不一定都是函数了,还有可能是NULL
//NULL的话不执行,而且最好是把这一项删除掉
for (let i = 0; i < pond.length; i++) {
let item = pond[i];
if (item === null) {
pond.splice(i, 1);
i--;
continue;
}
item(...arg);
}
}
}
window.Subscribe = Subscribe;
}(window);
- 发布订阅中数组塌陷

