1、工厂模式
为了避免每次创建对象都写相同的代码,将创建对象的过程放到一个函数中,每次创建对象时调用该函数即可。
定义函数,函数里面使用new Object()新建对象,并为其增加相应的属性。
function createPerson(name,age){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.sayName=function(){
return this.name;
}
return obj;
}
var person1=createPerson("keency",10);
var person2=createPerson("wylla",20);
2、构造函数模式
定义函数,该函数用于使用new 函数名()的方式来创建对象(用于创建对象的函数称为构造函数,因此该模式为构造函数模式)
构造函数模式,有以下特点:
没有显示的创建对象;
属性和方法添加到this中;
没有return;
作为构造函数的函数首字母要大写。
function Person(name,age){
this.name=name;
this.age=age;
this.sayName=function(){
return this.name;
}
}
var person1=new Person("keency",10);
var person2=new Person("wylla",20);
缺点:对于两个实例,他们的调用方法完全相同时,却要拥有两个不同的属性对象。
解决:将公共的函数,单独写到全局变量中。
function Person(name,age){
this.name=name;
this.age=age;
this.sayName=sayName;
}
function sayName(){
return this.name;
}
person1=new Person("keency",10);
person2=new Person("wylla",20);
问题:写到全局变量中的函数,只能在某个对象上进行调用,名不副实。
若有多个公共的函数,要写多个全局变量。
其他调用形式的构造函数:
作为普通函数的构造函数
Person("Bob",100);//this为window
window.sayName();//"Bob"
在另一个对象中调用的构造函数
var obj=new Object();
Person.call(obj,"Alice",25);
obj.sayName();//"Alice"
3、原型模式
为了解决构造函数公共函数的问题,将所有的属性都写到原型对象中,这样所有的属性都可以公用,不存在功能完全相同的两个不同的属性对象。
fucntion Person(){
}
Person.prototype.name="keency";
Person.prototype.age=10;
Person.prototype.sayName=function(){
return this.name;
}
var person1=new Person();
var person2=new Person();
person1.name="Bob";
console.log(person1.name);//"Bob"来自实例
console.log(person2.name);//"Keency"来自原型
采用此方式原型对象的属性可以动态追加,而后在person1和person2中也可调用追加的属性。
更简单的语法(不用一个一个添加原型对象中的属性而是直接重新定义一个原型对象)
function Person(){
}
Person.prototype={
constructor:Person,//①
name:"keency",
age:"10",
sayName:function(){return this.name;}
}
采用此方式,重新定义了Person的原型对象,Person.protype的constructor属性指向Object而不指向Person。因此需要增加代码中①部分,重新设置constructor属性。
问题:直接添加属性的方式会使constructor的enumerable变为true,不符合ECMAScript5的标准,因此应采用Object.denfineProperty的方式定义constructor属性。
若在创建了实例之后重新定义函数的原型对象,则实例的[[prototype]]仍指向原有的原型对象。
存在的问题:
一些不想公有的属性也公有了(包含引用类型值的属性,例如该属性为数组时)。因此需要采用方法4。
fucntion Person(){
}
Person.prototype={
constructor:Person,
name:"Keency",
age:"10",
friends:["Bob","Alice"],
sayName:function(){
return name;
}
}
var person1=new Person();
var person2=new Person();
person1.friends.push("Van");//调用对象上属性的方法,该对象没有该属性,于是向原型对象上查找
console.log(person1.friends);//"Bob","Alice","Van"
console.log(person2.friends);//“Bob","Alice","Van"
4、组合使用构造函数模式和原型模式
对象私有的部分放到构造函数中,公有的放到原型对象中。
fucntion Person(name,age){
this.name=name;
this.age=age;
this.friends=["Bob","Alice"]
}
Person.prototype={
constructor:Person,
sayName:function(){
return name;
}
}
var person1=new Person("Keency",10);
var person2=new Person("wylla",20);
person1.friends.push("Van");//调用对象上属性的方法,该对象有该属性
console.log(person1.friends);//“Bob","Alice","Van"
console.log(person2.friends);//“Bob","Alice"
5、动态原型模式
在构造函数中初始化原型(仅在必要的情况下(进行方法检查)),更符合OO语言的规则。
进行检查的目的在于,在第一次创建该构造函数的实例时需要在原型对象中添加公共函数,后面再创建实例时不需要再定义公共函数了。
fucntion Person(name,age){
this.name=name;
this.age=age;
this.friends=["Bob","Alice"];
if(typeof this.sayName!="function"){//只需要检查其中一个函数即可
alert(1);//只在第一次创建实例时弹出
Person.prototype.sayName=function(){
return this.name;
}
}
}
6、寄生构造函数模式
工厂模式和构造模式的结合。
函数内部采用工厂模式,调用的时候采用new 函数名()的构造函数模式。
无法判断该创建的对象是构造函数名对应的类型。
function Person(name,age){
var obj=new Object();
obj.name=name;
obj.age=age;
obj.sayName=function(){
return this.name;
}
return obj;
}
var person1=new Person("keency",10);
person1 instanceof Person;//false
person1 instanceof Object;//true
7、稳妥构造函数模式
没有公共属性而且其方法也不引用this。
function Person(name,age,job){
var obj=new Object();
o.sayName=function(){
return name;
};
return obj;
}