工厂模式
工厂模式通过函数接收参数来封装创建对象。
包括以下步骤:
1.创建封装函数
2.显示地创建对象
3.将接收的参数和方法赋值给该对象
4.将创建的对象返回给实例
如下面例子:
function createPerson(name, age, job) {
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function() {
alert(this.name);
}
return o;
}
var person1 = createPerson("Sam", 20, "Software Engineer");
var person2 = createPerson("Jack", 24, "Doctor");
构造函数模式
构造函数(constructor)方法与工厂模式有所不同,表现在:
1.没有在函数里显示地创建对象
2.直接将属性和方法赋值给了this对象
3.没有return语句
4.构造函数名称首字母应大写
创建Person的新实例,必须使用new
操作符。以这种方式调用构造函数会经历以下四个步骤:
(1)创建一个新对象
(2)将构造函数的作用域赋给新对象(于是this
指向这个新对象)
(3)执行构造函数中的代码(为该对象添加属性)
(4)返回新对象给实例
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.sayName = function() {
alert(this.name);
};
}
var person1 = new Person("Sam", 20, "Software Engineer");
var person2 = new Person("Jack", 24, "Doctor");
上面这种写法有一个缺点,就是由于作用域链的关系,每实例化一次Person构造函数都会创建一个新的sayName函数。两个实例中的同名实际上是两个独立开的函数,会造成不必要的开销。
alert(person1.sayName === person2.sayName); //false
因此我们可以像这样吧函数定义转移到构造函数之外:
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = sayName;
}
function sayName() {
alert(this.name);
}
var person1 = new Person("Sam", 20, "Software Engineer");
var person2 = new Person("Jack", 24, "Doctor");
//此时两个实例共享一个全局函数
alert(person1.sayName === person2.sayName); //true
当然构造函数本质其实也是函数,你也可以把它当做普通函数来使用:
//作为普通函数调用
Person("Greg", 27, "Doctor"); //添加到window
window.sayName(); //"Gray"
//在另一个对象的作用域中调用
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); //"Kristen"
原型模式
我们创建的没一个函数都有一个原型(prototype)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
使用原型对象的好处是我们不必在构造函数中定义对象实例的信息,而是将这些信息直接添加到原型对象当中。
function Person() {
}
Person.prototype.name = "Sam";
Person.prototype.age = 20;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = funtion() {
alert(this.name);
};
var person1 = new Person();
person1.sayName(); // "Sam"
var person2 = new Person();
person2.sayName(); // "Sam"
person1.sayName = person2.sayName // true
在创建实例时,我们仍然可以用new
方法来实例对象,但是新的实例的属性和方法是共享的。
构造函数和原型函数结合
这种方式集两种模式之长,每个实例都会有自己的一份构造函数中的实例属性副本,同时又共享着原型中的方法。
function Person(name, age, job) { //每个实例独有
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby","Court"];
}
Person.prototype = { //共享的方法
constructor : Person,
sayName : function() {
alert(this.name);
}
}
动态原型模式
这个方法简单的来说就是先将所有信息封装在构造函数中,然后通过判断说需要的函数是否存在来动态地初始化原型。
function Person(name, age, job) {
//属性
this.name = name;
this.age = age;
this.job = job;
//方法
if(typeof this.sayName != "function") { //不存在这个函数
Person.prototype.sayName = function() {
alert(this.name);
}
}
}
寄生构造函数模式
简单的来说就是:构造模式的外表 + 工厂模式的内心
这个方法用于在特殊情况下为对象创建构造函数。如:想创建一个具有自定方法的数组。
由于无法直接更改数组的构造函数,可以用寄生构造方法来封装一个所需函数:
function SpecialArray() {
//创建数组
var values = new Array();
//添加值
values.push.apply(values, arguments);
//添加方法
values.toPipedString = function() {
return this.join("|");
};
return values;
}
var friend = new Person("Nicholas", 29, "Writer");
friend.sayName(); //"Nicholas"
稳妥构造函数模式
在安全环境下,不使用new
和this
function Person(name, age, job) {
var o = new Object();
//可以在这里定义私有变量和函数
//添加方法
o.sayName = function() {
alert(name);
};
return o;
}
//在这个稳妥方法中,除了sayName()以外没有方法访问到name属性