
一、工厂模式
function createPerson(name,age,sex){
var o = {};
o.name = name;
o.age = age;
o.sex = sex;
o.sayName = function(){
alert(this.name)
}
}
var person1 = createPerson('小明',18,'女');
var person2 = createPerson('小西',20,'男');
工厂模式创建的‘人’是没有灵魂的,因为他们不能识别创建他们的‘爸爸’,也就是alert(person1 instanceof createPerson);//false 这是因为o对象在createPerson函数中重新new Object()了,所以createPerson不是o的原型了
而构造函数模式就解决了这个问题
二、构造函数模式
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.sayName = function(){
alert(this.name)
}
}
var person1 = new Person('小明',18,'女');
var person2 = new Person('小西',20,'男');
用这种new的方法创建出来的对象会自动获得一个constructor(构造函数)属性,这个属性,指向它的‘爸爸’,也就是Person。
构造函数虽然好用,但有一个缺点就是,在创建实例对象的时候,会把方法重新创建一遍。这会导致不同的作用域和标识符。alert(person1.sayName == person2.sayName)//false
** 解决办法:**
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
this.sayName = sayName
}
function sayName(){
alert(this.name)
}
var person1 = new Person('小明',18,'女');
var person2 = new Person('小西',20,'男');
把sayName函数作为全局函数,有一个指向函数Person的指针,person1和person2就可以访问同一个方法了。但这又会有一个新问题,sayName函数放在全局中,就能被其他对象调用,这是不太合理的,且不适用于封装。
这时候,原型模式就要登场了!
三、原型模式
在这个话题开始之前,我们应该先了解一下,property(原型):
了解property
1、每个函数都有property(原型)
2、每个对象都有_proto_(隐式原型)
3、对象是属性的集合,函数也是对象,所以函数既有property,又有_proto_
** 那么,prototy到底是什么呢?**
简单来说就是,把属性和方法添加到property(原型)上去,儿子们就可以通过一条线找到这些属性和方法,实现共享
function Person(){
}
Person.prototype.name = '小明';
Person.prototype.age = 18;
Person.prototype.sex = '女';
Person.prototype.sayName = function(){
alert(this.name)
};
var person1 = new Person();
person1.sayName()//小明
var person2 = new Person();
//person2.sayName()//小明
** 为什么‘儿子们’可以找到共享的方法呢? **
当创建一个函数爸爸的时候,会给爸爸一个prototype(原型)属性,这个属性会有一个constructor(自动得到的),这个属性会指向函数爸爸。也就是Person.prototype.constructo 指向 Person。
当创建了一个对象实例的时候,这个实例就会有一个_proto_(隐式原型),指向函数爸爸的prototype(原型)。这样说可能有点抽象,或许我们可以上个图!

- Person.prototype指向原型对象
- Person.prototype.constructor指回构造函数Person
- person1和person2都有一个属性,指向原型对象
- Person.prototype == person1(person2).proto
所以实现共享的本质是:当读取对象的属性时,1、看对象自己有没有这个属性或方法,如果找到了,就返回这个值 2、自己没有的话,就通 过_proto_ 指向的 prototype查找有没有这个属性或方法,如果有,就返回。
顺便附上作图工具:www.processon.com/
** 原型模式的缺点 **
- 不能自定义参数
- 属性是共享的,会对包含引用类型的值来说,产生致命问题
function Person(){}
Person.prototype={
constructor : Person,
name : '小明',
age : 18,
sex : '男',
friends ; ["小花","小夏"],
sayName : function(){
alert(this.name)
}
}
var person1 = new Person();
var person2 = new Person();
person1.friends.push(“小天”);
console.log(person1.friends);//"小花","小夏",“小天”
console.log(person2.friends);//"小花","小夏",“小天”
由于person1修改的是Person.prototype,这个共享的属性,所以person2的值也会受影响
四、构造函数模式+原型模式
这种方法才是最目前运用最广泛的方法,因为这种方法取两种模式的有点,构造函数不共享,就用来定义实例的属性,原型模式共享,就用来定义实例的方法。
function Person(name,age,sex){
this.name = name;
this.age = age;
this. sex = sex;
this.friends = ["小花","小夏"];
}
var person1 = new Person('小明',18,'女');
var person2 = new Person('小西',20,'男');
person1.push("小天");
console.log(person1.friends);//"小花","小夏",“小天”
console.log(person2.friends);//"小花","小夏"