单例模式:
**好处:**减少全局变量,全局对象被污染问题
实现:
-
懒汉式
let ShopCar = (function () { let instance; function init() { /*这里定义单例代码*/ return { buy(good) { this.goods.push(good); }, goods: [], }; } return { getInstance: function () { if (!instance) { instance = init(); } return instance; }, }; })(); let car1 = ShopCar.getInstance(); let car2 = ShopCar.getInstance(); car1.buy('橘子'); car2.buy('苹果'); console.log(car1.goods); //[ '橘子', '苹果' ] console.log(car1 === car2); // true -
饿汉式
面试题 -> 实现Storage,使得该对象为单例,基于 localStorage 进行封装。实现方法 setItem(key,value) 和 getItem(key)
class Storage {
static getInstance() {
if(!Storage.instance) {
Storage.instance = new Storage()
}
return Storage.instance
}
getItem(key) {
return localStorage.getItem(key)
}
setItem(key,value) {
return localStorage.setItem(key,value)
}
}
Storage.getInstance()
**思想:**一个类只能创建一个实例,判断有没有创建过实例,有创建过则直接返回,否则创建一个实例并返回
懒汉式在类加载时,不创建实例,因此类加载速度快,但运行时获取对象的速度慢;支持延迟加载饿汉式在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快
工厂函数:
**好处:**解决了代码复用性问题,减少页面的中的冗余代码。
思想:
- 入口——函数参数
- 加工——具体函数功能
- 出口——函数返回值
// 入口
function createPerson(name, age) {
//加工过程
var obj = {};
obj.name = name;
obj.age = age;
obj.info = function () {
console.log(obj.name, obj.age);
}
// 出口
return obj;
}
var p1 = createPerson('xiaopei' , 26);
p1.info();
var p2 = createPerson('xiaoqiangh' , 25);
p2.info();
console.log(p1.info == p2.info) // false
两个问题:
- 可读性问题:不知道这个函数具体是要来当什么用的,用于功能函数还是工厂模式。
- 空间性问题:里面的function 不是通用的,不同的存储空间,每次调用都会创建。
构造模式:
**好处:**解决了工厂模式的可读性
实现:
function CreatePerson(name, age) {
this.name = name;
this.age = age;
this.info = function () {
console.log(this.name, this.age);
}
}
var p1 = new CreatePerson('xiaopei' , 26);
p1.info();
var p2 = new CreatePerson('xiaoqiangh' , 25);
p2.info();
console.log(p1.info == p2.info) // false
**问题:**工厂函数的空间问题还存在
原型模式:
**好处:**解决了工厂模式的空间性问题
function CreatePerson() {}
CreatePerson.prototype.name = '';
CreatePerson.prototype.age = 0;
CreatePerson.prototype.play = []
CreatePerson.prototype.info = function () {
console.log(this.name, this.age,this.play);
}
var p1 = new CreatePerson();
p1.name = 'xiaopei'
p1.play.push('game')
p1.info(); // xiaopei 0 ["game"]
var p2 = new CreatePerson();
p2.name = 'xiaoqiang'
p2.info(); // xiaoqiang 0 ["game"]
console.log(p1.info == p2.info) // true
**问题:**类型为引用类型的时候,对它的增删改都是同一个地址。改一个就等于改多个
混合模式:
好处:即解决了可读性问题,又解决了空间占用问题,
function CreatePerson() {
this.name = '';
this.age = 0;
this.play = []
}
CreatePerson.prototype.info = function () {
console.log(this.name, this.age,this.play);
}
var p1 = new CreatePerson();
p1.name = 'xiaopei'
p1.play.push('game')
p1.info(); // xiaopei 0 ["game"]
var p2 = new CreatePerson();
p2.name = 'xiaoqiang'
p2.info(); // xiaoqiang 0 []
console.log(p1.info == p2.info) // true
思想:使用构造函数的属性命名方法,原型模式的方式定义方法。
策略模式:
好处:
-
避免大量冗余的代码判断,比如if else等
**思想:**策略模式将不同算法进行合理的分类和单独封装,让不同算法之间可以互相替换而不会影响到算法的使用者
实现:
// 定义几个策略类
var PaymentMethodStrategy = {
BankAccount: function (money) {
return money > 50 ? money * 0.7 : money;
},
CreditCard: function (money) {
return money * 0.8;
},
Alipay: function (money) {
return money;
},
};
/*环境类*/
var userPay = function (selectedStrategy, money) {
return PaymentMethodStrategy[selectedStrategy](money);
};
console.log('银行卡支付价格为:' + userPay('BankAccount', 100)); //70
console.log('支付宝支付价格为:' + userPay('Alipay', 100)); //100
console.log('信用卡支付价格为:' + userPay('CreditCard', 100)); //80
参考文章: