1.工厂模式
用函数来封装以特定接口创建对象的细节
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("Nicholas", 29, "Software Engineer");
2.构造函数模式
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
式调用构造函数会经历以下4个步骤:
(1) 创建一个新对象;
(2) 将构造函数的作用域赋给新对象(因此this 就指向了这个新对象);
(3) 执行构造函数中的代码(为这个新对象添加属性);
(4) 返回新对象。
对比工厂模式可以知道类型:
alert(person1 instanceof Object); //true
alert(person1 instanceof Person); //true
调用方法:
// 当作构造函数使用(new)
var person = new Person("Nicholas", 29, "Software Engineer");
person.sayName(); //"Nicholas"
// 作为普通函数调用(没有new)
Person("Greg", 27, "Doctor"); // 添加到window
window.sayName(); //"Greg"
// 在另一个对象的作用域中调用
//使用call()(或者apply())在某个特殊对象的作用域中
调用Person()函数
var o = new Object();
Person.call(o, "Kristen", 25, "Nurse");
o.sayName(); //"Kristen"
3.原型模式
每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象。
当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象,与构造函数没有直接的关系。只有一个原型,空构造器。
var person1 = new Person();
var person2 = new Person();
alert(person1.name); //"Nicholas"——来自原型
alert(person1.hasOwnProperty("name")); //false 检查name来自实例还是原型
alert("name" in person1); //true无论该属性存在于实例中还是原型中,只要能够访问name
person1.name = "Greg";
alert(person1.name); //"Greg"——来自实例
alert(person1.hasOwnProperty("name")); //true
当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性。
var keys = Object.keys(Person.prototype);
alert(keys); //"name,age,job,sayName"
var p1 = new Person();
p1.name = "Rob";
p1.age = 31;
var p1keys = Object.keys(p1);
alert(p1keys); //"name,age"
原型模式缺点:
(1) 省略了为构造函数传递初始化参数这一环节,结果所有实例在
默认情况下都将取得相同的属性值;
(2) 对于包含引用类型值的属性来说,问题比较突出。
function Person(){
}
Person.prototype = {
…
friends : ["Shelby", "Court"],
…
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Court,Van"
alert(person2.friends); //"Shelby,Court,Van"
alert(person1.friends === person2.friends); //true
4.组合使用构造函数模式和原型模式
为了解决原型模式在引用类型上的问题。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。
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);
}
}
5.动态原型
跟4差不多都是混合,但是进行了封装。
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);
};
}
}
6.寄生构造函数模式(最好不要用)
除了使用new 操作符并把使用的包装函数叫做构造函数之外,这个模式跟工厂模式其实是一模一样的。
function Person(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 friend = new Person("Nicholas", 29, "Software Engineer");
7.稳妥构造函数模式(适合在一些安全的环境中)
function Person(name, age, job){
//创建要返回的对象
var o = new Object();
//可以在这里定义私有变量和函数
//添加方法
o.sayName = function(){
alert(name);
};
//返回对象
return o;
}
var friend = Person("Nicholas", 29, "Software Engineer");
friend.sayName(); //"Nicholas",除了使用sayName()方法之外,没有其他办法访问name 的值