工厂模式
工厂模式是软件工程领域一种广为人知的设计模式,而由于在ECMAScript中无法创建类,因此用函数封装以特定接口创建对象。其实现方法非常简单,也就是在函数内创建一个对象,给对象赋予属性及方法再将对象返回即可。
function createPerson(name, age) {
var o = new Object();
o.name = name;
o.age = age;
o.sayName= function() {
alert(this.name);
}
return o;
}
var person1 = createPerson('a', '22');
可以看到工厂模式的实现方法非常简单,解决了创建多个相似对象的问题,但是工厂模式却无从识别对象的类型,因此出现了构造函数模式
构造函数模式
ECMAScript中构造函数可以创建特定类型的对象,其实现方法如下:
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
alert(this.name);
}
}
var person1 = new Person('a', '22');
console.log(person1 instanceof Person); // true,
判断person1是否是Person的实例,即解决了工厂模式中不能
这个例子与工厂模式中除了函数名不同以外,
函数名首写字母为大写 (虽然标准没有严格规定首写字母为大写,但按照惯例,构造函数的首写字母用大写
没有显示的创建对象
直接将属性和方法赋值给了this对象
没有return语句
使用new创建对象
能够识别对象(这正是构造函数模式胜于工厂模式的地方)
构造函数的问题:
每次创建实例的时候都要重新创建一次方法(理论上每次创建对象的时候对象的属性均不同,而对象的方法是相同的),然而创建两次完全相同的方法是没有必要的
原型模式
我们创建的每个函数都有prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。使用原型对象的好处就是可以让所有对象实例共享它所包含的属性及方法。
function Person() {
}
Person.prototype.name = 'a';
Person.prototype.age = 22;
Person.prototype.friend = ['b', 'c', 'd', 'e'];
Person.prototype.sayName = function() {
alert(this.name );
}
原型模式缺点:
首先,它省略了构造函数传递初始化参数这一环节,结果所有实例在默认情况下都取得了相同的属性值,原型模式的最大问题在于共享的本性所导致的,由于共享,因此因此一个实例修改了引用,另一个也随之更改了引用。因此我们通常不单独使用原型,而是结合原型模式与构造函数模式。
简单原型模式
function Person() {
}
Person.prototype={
name = 'a';
age = 22;
friend = ['b', 'c', 'd', 'e'];
sayName = function() {
alert(this.name );
}
}
简单原型模式会重写原型对象,原型中的constructor属性不再指向构造函数。
混合模式(原型模式 + 构造函数模式)
function Person(name,age) {
this.name = name;
this.age = age;
this.friends = ['e','f','g' ]
}
Person.prototype.sayName= function() {
alert(this.name )
}
var person1 = new Person('a',22,)
var person2 = new Person('b',23 );
person1.friend.pop();
alert(person1.friends); // 'f','g'
alert(person2.friends);// 'e','f','g'
混合模式中构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性。每个实例都会有自己的一份实例属性,但同时又共享着方法,最大限度的节省了内存。另外这种模式还支持传递初始参数.
动态原型模式
动态原型模式将所有信息封装在了构造函数中,而通过构造函数中初始化原型(仅第一个对象实例化时初始化原型),这个可以通过判断该方法是否有效而选择是否需要初始化原型。
function Person(name, age) {
this.name = name;
this.age = age;
if (typeof this.sayName= "function") {
// 这段代码只执行了一次
Person.prototype.sayName = function() {
alert(this.name);
}
}
}
var person3 = new Person('c', 18),
person3.sayName();