Skip to content

《JavaScript 高级程序设计》 读书笔记--创建对象方法的演化

约 1196 字大约 4 分钟

JavaScript前端读书笔记

2018-12-11

0. 花括号

  • 产生的问题: 代码重复。

创建一个类,最简单的莫过于一对花括号。就像下面这样,简单、直接。

let p1 = {
  name: 'KizunaAi',
  age: 2,
  sex: 'f',
  getName: function(){
    return this.name
  }
}

但是,当我们要创建 10 个类似于 p1 的对象时,代码的重复就成了一个头痛的事情了。于是,我们就利用函数和 Object,搭建出工厂模式。

1. 工厂模式

  • 解决问题:重复代码问题。只要定义一次,就能创建相同格式的对象。
  • 产生的问题:没有对象类型,实例都是 Object 类型;内部方法重复生成会占空间。

普通函数内包装了一个 Object,然后通过 new Object() 返回我们要的实例。在软件工程中是个经典的模式,不过现在基本被构造函数模式代替了。

示例代码如下:

function CreatePerson(name, age, sex){
  // 在函数内部生成 Object 的实例
  let o = new Object()
  o.name = name
  o.age = age
  o.sex = sex

  o.getName = function(){
    return this.name
  }

  return o
}

// 普通调用函数方法获取实例
let p1 = CreatePerson('KizunaAi', 2, 'f')
let p2 = CreatePerson('Luna', 100, 'f')

工厂模式彻底解决了代码重复的问题,但是留下实例无法确定对象类型的问题,这个主要是因为实例的 constructor 函数指向的是 Object,为了解决这个问题,就有了后面的构造函数方法。

2. 构造函数

  • 解决问题:构造函数 new 出来的实例,有对象类型。即可以使用 instanceof 方法进行判断。
  • 产生的问题:方法(函数)定义在构造函数内部时,每次创建实例时都会重复创建方法,因此仍然会有资源占用的问题。
function Person(name, age, sex){
  this.name = name
  this.age = age
  this.sex = sex

  this.getName = function(){
    return this.name
  }
}

// 我们最常用的 new 来啦
let p1 = new Person('KizunaAi', 2, 'f')
let p2 = new Person('Luna', 100, 'f')

构造函数方法解决了实例的对象类型问题,也基本取代了工厂模式。但是对于每个实例的会创建各自独立的方法仍然没有解决。这个问题就交给了原型模式。

3. 原型模式

  • 解决问题:实例的方法可以共享,可以避免资源占用的问题。
  • 产生的问题:属性也会共享,那么一旦有一个实例修改了属性,所有的实例对应的属性也会被修改。

我们创建的每个函数都有一个 prototype 属性,这个属性的用处就是可以让所有的实例共享属性和方法。这样一来,我们把方法挂到 prototype 上就能避免实例方法的重复创建的问题了。

function Person(){}

Person.prototype.name = 'KizunaAi'
Person.prototype.age = 2
Person.prototype.sex = 'f'
Person.prototype.getName = function(){
  return this.name
}

let p1 = new Person()
// p1.name = KizunaAi

原型模式解决了实例方法独自创建的问题,但是原型上的公共属性却也会被波及,但这个其实并不是什么问题。到这里基本问题就基本都解决了,只要优化一下即可。

4. 组合模式(构造 + 原型)

所以顺着上面的问题,就能明白为什么说属性要放在构造函数里,方法要挂到 prototype 上了。而这么一来,也就是我们用的最多的书写类的方法了。

function Person(name, age, sex){
  this.name = name
  this.age = age
  this.sex = sex
}

Person.prototype.getName = function(){
  return this.name
}

let p1 = new Person('KizunaAi', 2, 'f')
let p2 = new Person('Luna', 100, 'f')

小结

尽管高程中创建对象有 7 中模式,但顺着问题就能发现组合模式解决了前面留下的所有问题。可以说是最合适的模式了。之后的模式其实都是前面模式的衍生和变种,感觉平时也用不上也就不再展开了。

说实在的,在日常的工作中会用一对花括号和一个 new 基本就能解决 90% 的问题了。真的要自己去了解为什么这么做的情况并不多(我自己除了在 Node 中会写写类,在前端感觉真的用不到,除非是自己写框架吧)

但有时候去了解一下常用的方法背后的故事,不也是一件挺有意思的事情吗?


其实我原本主要是去看继承的(这一块平时用得少,一直是一知半解的状态),在看的过程中发现继承与对象创建的关系十分密切。看完对象的创建再看继承会容易理解很多。所以下一篇就是继承的学习笔记了。