开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第2天,点击查看活动详情
前言
什么是设计模式?
(Design pattern)
代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。————《菜鸟教程》
总而言之,设计模式就是为了解决软件开发中一些遇到问题的目前解决最佳方案,是由软件工程师们一步一步摸索出来的,使来这些问题轻松化,简单化。
本文主要讲解js设计模式中的单例模式以及装饰器模式
单例模式
核心:保证一个类,只有一个实例,并提供一个访问它的全局访问点
实现一个简单的单例模式
下面我们来看一个简单的单例模式
function Person(name, age) {
this.name = name;
this.age = age
}
let jitao = new Person('计涛', 20)
let yc = new Person('严辰', 21)
console.log(jitao);
console.log(yc);
如图所示,打印出来的结果是两个实例,并不满足满足单例模式,那我们该如何改呢?
let Person = (function () {
let instance = null
return function (name, age) {
this.name = name
this.age = age
if(instance){
return instance
}
return instance = this
}
})()
// function Person(name, age) {
// this.name = name;
// this.age = age
// }
let jitao = new Person('计涛', 20)
let yc = new Person('严辰', 21)
console.log(jitao);
console.log(yc);
console.log(jitao===yc);
在这里,我们定义一个快速执行函数Person
,在其中返回一个函数(下面简称返回函数),那么我们下面new的实际上就是这个返回函数,然后这个返回函数的外面我们定义一个instance
,值为null,然后让返回函数的值传入我们定义的instance
,这样我们创建第二个实例的时候,返回的便会是我们第一次创建实例的值,从而完成了初步的单例模式的设计。
- 以上代码通过自执行函数和闭包将
instance
封装起来。并且返回了真正的单例构造方法。
但如果哪天,我们需要在其中添加更多的元素,但又不想改写Person,我们该怎么办呢?我们可以通过代理来解决
通过代理实现单例模式
function Person(name, age) {
this.name = name;
this.age = age
}
Person.prototype.sayHello = function () {
console.log(this.name)
}
let jitao = new Person('计涛', 20)
let yc = new Person('严辰', 21)
console.log(jitao)
console.log(yc)
console.log(jitao === yc)
我们先定义一个Person类,然后在它的原型上定义一个sayHello的方法,那么我们知道,这里不是单例模式,那如何在不改变上面代码的情况下建立一个单例模式呢?这里我们就可以建立一个代理类,来实现单例模式。
function Person(name, age) {
this.name = name;
this.age = age
}
Person.prototype.sayHello = function () {
console.log(this.name)
}
let personProxy = (function () {
let instance = null
return function (name,age) {
if (instance) {
return instance
}
return instance = new Person(name, age)
}
})()
let jitao = new personProxy('计涛', 20)
let yc = new personProxy('严辰', 21)
console.log(jitao)
console.log(yc)
console.log(jitao === yc)
jitao.sayHello();
yc.sayHello();
我们定义一个personProxy
的代理方法,在这里new Person
并不是单例的,真正的单例是我们定义的personProxy
,它作为代理来实现了我们的单例模式。
装饰器模式
装饰器模式(Decorator)也可称之为装饰者模式,在不改变原有对象的基础上,对其进行包装,拓展,使原有对象可以满足更加复杂的需求。
增强对象
举个简单的例子,我们定义一个学生类,要求学生需要会HTML、CSS、JS,
function Student(){}
Student.prototype.study = function(){
console.log('html');
console.log('css');
console.log('js');
}
var jitao = new Student();
但为了找到工作,我们更加要求学生会vue,react,那怎么办呢?我们便对其进行增强
function Student(){}
Student.prototype.study = function(){
console.log('html');
console.log('css');
console.log('js');
}
// 定义一个装饰类,对student类进行增强
function Decorator(someBody){
this.someBody = someBody
this.someBody.ability = 'ability--'
return this.someBody
}
var jitao = new Student();
jitao = new Decorator(jitao)
console.log(jitao.ability);
可以看到我们在jitao
这个对象身上增强了一个属性ability
,而且可以看到,jitao
这个属性依旧是Student里面的。
增强方法
上述是增强了一个对象,那么如何增强一个方法呢?
function Student() { }
Student.prototype.study = function () {
console.log('html');
console.log('css');
console.log('js');
}
// 定义一个装饰类,对Student类进行增强
function Decorator(someBody) {
this.someBody = someBody
// 把之前study方法备份一下
this.someBody._study = someBody.study
// 把Decorator构造器中生成的对象中的study,覆盖掉之前的study方法
this.someBody.study = this.study
return this.someBody
}
Decorator.prototype.study = function(){
// 调用原本的study方法
this._study();
console.log('vue');
console.log('react');
}
let jitao = new Student();
jitao = new Decorator(jitao)
jitao.study()
在Decorator中,我们利用它本身构造器构造出来的study方法,覆盖了它之前本身的study方法,然后在其原型上调用原本的stydy方法,再对其进行增强,从而达到了增强整个类的目的。
- 注意:目前ES中
Decorator
还处于提案阶段,各大浏览器和node,均未公开支持这一特性.如果想要使用,则需要借用babel
的一个插件babel-plugin-transform-decorators
才可以.
结语
js的设计模式是开发中不可或缺的一部分,我们要加强学习,小编学识尚浅,有不足之处,请纰漏
暂无评论内容