JavaScript的设计模式

JavaScript的设计模式

工厂模式

用于抽象创建特定对象的过程

1
2
3
4
5
6
7
8
9
10
11
12
function createPerson (name, age, job) {
let o = new Object()
o.name = name
o.age = age
o.job = job
o.sayName = function () {
console.log(this.name)
}
return o
}
let p1 = createPerson('Greg', 27, 'Doctor')
console.log(p1)
  • 可以用不同的参数调用这个函数,每次返回包含的参数和方法的对象
  • 可以解决创建多个类似对象问题
  • 不足:没有新创建的对象是什么类型

构造函数模式

自定义构造函数,以函数的形式为自己的对象类型定义属性和方法。

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
28
29
30
31
32
33
34
35
36
function Person (name, age, job) {
this.name = name
this.age = age
this.job = job
this.sayName = function () {
console.log(this.name)
}
}
let p1 = new Person('Nicholas', 29, 'Software Enginner')
console.log(p1.name) // Nicholas
console.log(p1 instanceof Object) // true
console.log(p1 instanceof Person) // true

let p2 = new Person('Jack', 29, 'Software Enginner')
console.log(p2.name) // Nicholas
console.log(p2 instanceof Object) // true
console.log(p2 instanceof Person) // true
console.log(p1.sayName == p2.sayName) // false


/**
* sayName函数定义在构造函数外部,sayName等于全局sayName函数
* p1 和 p2 共享了定义全局作用域上的sayName函数
* 但是全局作用域也被搞乱,那个函数实际只能在一个函数调用
* 如果对象需要多个方法,只能在全局作用域定义多个函数
*/
function Person2 (name, age, job) {
this.name = name
this.age = age
this.job = job
this.sayName = sayName
}

function sayName () {
console.log(this.name)
}

和工厂模式的不同之处

  • 没有显示创建对象
  • 属性和方法都赋值给this\
  • 没有return

new 过程

  • 内存创建一个新的对象
  • 这个新的对象内部的prototype特性被赋值为构造函数的prototype属性
  • 造函数内部的this被赋值为这个新的对象
  • 执行构造函数的代码
  • 如果构造函数返回非空对象,则返回该对象,否则,返回刚创建的对象

优势

  • 相比较工厂模式,自定义构造函数可以确保实例被标识为特定类型

问题

  • 定义的方法在每个实例上都创建了一遍, 因为函数是对象,每次定义函数,都会初始化一个对象
  • p1 和 p2都有名为sayName方法,但两个方法不是同一个Function实例

原型模式

每个函数都会创建一个 prototype 属性,这个属性是一个对象,包含应该由特定引用类型的实例共享的属性和方法.这个对象就是通过调用构造函数创建的对象的原型。使用原型对象的好处是,在它上面定义的属性和方法可以被对象实例共享。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function Person () {}
Person.prototype.name = 'Jack'
Person.prototype.age = 20
Person.prototype.job = 'Software Engineer'
Person.prototype.sayName = function () {
console.log(this.name)
}
let p1 = new Person()
p1.sayName()
let p2 = new Person()
p2.sayName()
console.log(p1.sayName == p2.sayName) // true
console.log(typeof Person.prototype);
console.log(Person.prototype);

问题:共享特性