理解 函数模式

工厂模式

说明:用函数来封装以特定接口创建对象的细节

优点:解决创建多个相似对象

缺点:不能识别对象(知道一个对象的类型)构造函数可解决该问题

我对这句话的理解是,因为工厂函数只是在函数内部创建了一个新的对象,并赋给这个对象一些属性和方法,然后返回这个对象。函数的 constructor 属性(构造函数)是用来识别对象类型的,然而工厂函数本身没有被赋予任何属性和方法,所以不能识别对象类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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;
}
// 函数 createPerson() 只是封装函数的外包结构,实际是里面新建的对象 o 在执行操作

// 调用过程是一个简单的函数调用形式
var person1 = createPerson('Echo', 29, 'Software Engineer');// Echo
var person2 = createPerson('Greg', 27, 'Doctor');// Greg

构造模式

说明:必须使用 new 操作符来创建实例(使用 new 调用的函数才叫构造函数),函数名始终都是以大写字母开头(非构造函数以小写字母开头)

优点:可以将它的实例标志为一种特定的类型

缺点:每个方法都要在每个实例上创建一遍 (不同实例上的同名函数是不相等的)原型函数可解决该问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function Person(name, age, job) {
// 直接在将属性和方法赋给 this 对象
this.name = name;
this.ahe = age;
this.job = age;
this.sayName = function () {
alert(this.name);
}
// 没有 return 语句
}

// person1 和 person2 的 constructor (构造函数)属性(最初这个属性是用来标识对象类型的)指向 Person,
// 但现在用 instanceof 操作符
// person1 和 person2 既是 object 的实例,也是 Person 的实例,因为所有对象均继承自 Object(在浏览器中就是 window 对象)
var person1 = new Person('Echo', 29, 'Software Engineer');// Echo
var person2 = new Person('Greg', 27, 'Doctor');// Greg

alert(person1 instanceof Object); // true
alert(person2 instanceof Object); // true

alert(person1 instanceof Person); // true
alert(person2 instanceof Person); // true

// 不同实例上的同名函数是不相等的
alert(person1.sayName === person2.sayName()); // false

使用 new 操作符调用函数,会经历一下过程:

  1. 创建一个对象
  2. 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象)
  3. 执行构造函数重的代码(为这个新对象添加属性)
  4. 返回新对象
⚠️注意:以这种方式定义的构造函数是定义在 Global 对象中的

原型模式

说明:通过调用构造函数创建一个新实例后,该实例内部将包含一个指针(内部属性),指向构造函数的原型对象。

优点:所有对象实例共享它所包含的属性和方法

缺点:原型对象的最大问题就是共享所有属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function Person() {};

Person.prototype.name = 'Echo';
Person.prototype.age = 29;
Person.prototype.job = 'Software';
Person.prototype.sayName = function () {
alert(this.name);
};
var person1 = new Person;
person1.sayName();// 'Echo'
var person2 = new Person;
person2.sayName();// 'Echo'

//person1 和 person2 调用的是同一组属性和方法
alert(person1.sayName == person2.sayName);// true

// Person.prototype 指向 Person 函数
// Person.prototype.constructor 指向 Person 函数的原型对象

// 原型对象的另一种实现方式是对象字面量
Person.prototype = {
name: 'Echo',
age: 29,
sayName: function () {
alert(this.name);
}
}