对象字面量

1
2
3
4
5
6
7
8
var person = {
name: "Nicholas",
age: 29,
job: "Software Engineer",
sayName: function() {
alert(this.name);
}
}

缺点是使用同一接口创建很多对象,会产生大量重复的代码。

工厂模式

1
2
3
4
5
6
7
8
9
10
11
12
13
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");
var person2 = createPerson("Greg", 27, "Doctor");

缺点是不能识别对象的类型(即怎样知道一个对象的类型,即使用instanceof识别)。

构造函数模式

1
2
3
4
5
6
7
8
9
10
11
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");
var person2 = new Person("Greg", 27, "Doctor");

这里在复习一下使用new操作符后的执行过程:

  1. 创建一个新对象。
  2. 将构造函数作用域执行新对象(this指向了新对象)。
  3. 执行构造函数中的代码。
  4. 返回新对象。

构造函数中的缺点就是,每个方法都要在每个实例上重新创造一遍,ECMAScript中Function也是对象,因此定义一个函数也就是实例化一个对象,导致不同实例上的同名函数是不等的。

1
2
3
4
5
6
function Person(name, age, job) {
this.name = name;
this.ag = age;
this.job = job;
this.sayName = new Function("alert(this.name)");
}

组合构造函数模式和原型模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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);
}
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");

实例的属性都是在构造函数中定义的,所有实例共享原型链中定义的constructor方法和sayName()方法,而修改其中一个friends并不会影响另一个friends。

动态原型模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
}
}
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
person1.sayName();

这段代码只会在初次调用构造函数时才会执行。此后,原型已经初始化,不需要做什么修改。