关于js的设计模式(简单工厂模式,构造函数模式,原型模式,混合模式,动态模式)

关于js的各大模式,还有很多东西没有了解到,接触的越多,越发觉得这东西很有用。

<1>工厂模式

简单来说就是封装后的代码,简单的工厂模式是很好理解的,关于它的作用,就是利用面向对象的方法,把一些对象封装,使一些占用空间多的,重复的代码封装起来。实现方法非常简单,也就是在函数内创建一个对象,给对象赋予属性以及方法再将对象返回即可。

function creatper(name,age){  

var per=new Object(); //原料

//加工

 per.name=name;

 per.age=age;  

per.sayHi=function(){

  console.log(per.name+''+per.age);  }  

return per; //出厂

}

var me=creatper('katherine',22);

me.sayHi();

console.log(me.name);

可以看出,使用工厂模式,可以重复调用这个per函数来生成不同属性值得对象,这就像工厂一样,批量生产,里面的原料,加工,出厂都很清晰。但是你会发现工厂模式是无法识别对象的类型,因为全都是object,不像Date,Array等,但是构造函数就不是了。这还只是简单的工厂模式,复杂的工厂模式(抽象模式)等以后再回来详细了解。

<2>构造函数模式

ECMAScript中构造函数可以用来创建特定对象,类似于Array,Date等原生的js对象

function Student(name,age,classa){
 this.name=name;
 this.age=age;
 this.classa=classa;
 this.sayHello=function(){
  console.log(this.name,this.age,this.classa);
 }
}
var me=new Student("xiaoai",22,"大三");
console.log(me.classa);
me.sayHello();
console.log(me instanceof Student);//true

由代码可以看出,于工厂模式除了函数名不同以外,还要注意:构造函数名的首字母大写(不过好像没有严格规定)。构造函数也没有显示创建的对象,使用了this,直接把属性和方法赋值给了this对象。没有return语句,实例化的时候要使用new,而且它能够识别对象(这正是构造函数模式胜于工厂模式的地方)。

构造函数虽然好用,但也有很大的缺点,就是每次创建实例的时候都要重新创建一次方法,实际应用中,每次创建对象的时候属性值不同,而对象的方法却是相同的,所以创建两次完全相同的方法是没有必要的,因此有人会说可以把函数方法放到对象外面。如下:

function Student(name,age,classa){
 this.name=name;
 this.age=age;
 this.classa=classa;
 
}
function sayHello(){
  console.log(this.name,this.age,this.classa);
 }
var me=new Student("xiaoai",22,"大三");
console.log(me.classa);
me.sayHello();
console.log(me instanceof Student);

这样一改,就把sayhello函数设置成了全局函数,这样一来Student的每一个实例访问的都是同一个函数,可是,在全局作用域中定义一个只供student使用的函数,就显得有些过分了,如果在全局作用域中定义许多这样仅供特定对象使用的方法,那就太浪费空间了,显然也失去了面向对象所注重的封装性了,因此完全可以使用原型解决这个问题。

<3>原型模式

js规定每一个创建的函数都有prototype(原型)属性,这个属性是指针,指向一个对象,而这个对象的用途是包含由特定类型的所有实例所共享的属性和方法,使用原型对象就可以让所有实例对象均包含这些属性及方法。

function per(){}

per.prototype.name='xiaoai';

per.prototype.age=22;

per.prototype.course=['php','javascript','java','C#'];

per.prototype.say=function(){

 console.log(this.name+this.age+this.course);

}

var per1=new per();

var per2=new per();

per1.name='katherine';

per1.course.push('Html5');

per1.say();

per2.say();

per2.course.pop();

关于原型模式的缺点,我想也是很明显的,它省略了构造函数传递初始化参数这一环节,结果所有实例均在默认情况下取得了相同的属性值,虽然你可以在后来做出更改,但一点都不方便,这样还不是最大的问题,原型模式最大的问题是在于共享的本性所导致的,由于共享,因此一个实例修改了引用,另一个也随之更改了属性。因此一般不会单独使用原型模式。

<4>混合模式(原型模式+构造函数)

function per(name,age,course){

this.name=name;

this.age=age;

this.course=course;

}

per.prototype.say=function(){

 console.log(this.name+this.age+this.course);

}

var per1=new per('katherine',22,['C#','java','PHP','Javascript']);

var per2=new per ('xiaoai',21,['oracle','mysql','nodejs','html5']);

per1.say();

per2.say();

per1.course.pop();

per1.say();

per2.say();

由代码可以看出混合模式的分工:构造函数用于定义实例的属性,而原型模式用于定义方法和一些共享的属性。每个实例都会有自己的属性,但同时又共享着方法,最大限度的节省了内存。另外这种模式还支持传递初始参数。使用最广泛。

<5>动态模式

function per(name,age,course){  

this.name=name;

 this.age=age;

 this.course=course;

 if(typeof this.say!='function'){  

       per.prototype.say=function(){  

          console.log(this.name+this.age+this.course);

         }

  }

}

var per1=new per('katherine',22,['C#','java','PHP','Javascript']);

 var per2=new per('xiaoai',22,['oracle','mysql','nodejs','html5']);

 per1.say();

 per2.say();  

per1.course.pop();  

per1.say();

 per2.say();

动态原型模式将所有的信息都封装进了构造函数中,通过构造函数中初始化原型,仅第一个对象实例实例化时初始化,通过判断该方法是否有效存在而选择是否需要初始化。大白话就是:如果去掉if的话,每new一次(即每当一个实例对象生产时),都会重新定义一个新的函数,然后挂到per.prototype.say上,而实际上,只需要定义一次就够了,因为所有的实例都会共享此属性的,所以如果去掉if的话,会造成没有必要的时间和空间的浪费,而加上if后,只在new第一次实例化时会定义say方法,之后都不会再定义了。可以看出对于这种模式创建的对象,是最好的了。

本文章参考了http://www.jb51.net/article/53823.htm,只供本人学习笔记使用。

原文地址:https://www.cnblogs.com/xiaoai-tang/p/6575107.html