对象字面量
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操作符后的执行过程:
- 创建一个新对象。
- 将构造函数作用域执行新对象(this指向了新对象)。
- 执行构造函数中的代码。
- 返回新对象。
构造函数中的缺点就是,每个方法都要在每个实例上重新创造一遍,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();
|
这段代码只会在初次调用构造函数时才会执行。此后,原型已经初始化,不需要做什么修改。