首页 > 代码库 > 面向对象-读书笔记

面向对象-读书笔记

一、工厂模式

鉴于ECMAScript无法创建类,所以开发人员发明了一种函数,用函数来封装以特定接口创建对象的细节。举栗:

function createPerson(name,age,job){
  var o = new Object();
  o.name = name;
  o.age = age;
  o.job = job;
  o.sayName = function(){
      console.log(this.name);  
  } 
   return o;       
}  

var person1 = createPerson("Andy",28,"Actor");
var person2 = createPerson("Lily",22,"Nurse");

函数createPerson()能够根据接收的参数来构建一个包含所有必要信息的Person对象。可以无数次调用这个函数,每次它都会返回一个包含三个属性一个方法的对象。

工厂模式虽然解决了创建多个相似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)。

二、构造函数

举栗:

function Person(name,age,job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = function(){
    console.log(this.name);
  }        
}

var person1 = new Person("Andy",28,"Actor");
var person2 = new Person("Lily",22,"Nurse");

Person()和createPerson()之间的不同:

  a.没有显式地创建对象;

  b.直接将属性和方法赋给了this;

  c.没有return语句;

  d.函数名第一个字母大写,主要为了区别于其他函数。

要创建Person的新实例,必须使用new操作符。用这种方式调用构造函数会经历以下4个步骤:

  a.创建一个新对象;

  b.将构造函数的作用域赋给新对象(因此this就指向了这个新对象);

  c.执行构造函数中的代码(为这个新对象添加属性);

  d.返回新对象。

例子的最后,person1和person2分别保存这个Person的一个不同的实例。这两个对象都有一个constructor(构造函数)属性,该属性指向Person。验证如下:

console.log(person1.constructor == Person);   //true
console.log(person2.constructor == Person);   //true

 对象的constructor属性最初是用来标识对象类型的,但是用instanceof检测对象类型更好一些。上面的例子中创建的所有对象既是Object的实例,也是Person的实例。验证如下:

console.log(person1 instanceof Object);     //true
console.log(person1 instanceof Person);     //true

console.log(person2 instanceof Object);     //true
console.log(person2 instanceof Person);     //true

构造函数模式胜过工厂模式的地方在于:创建自定义的构造函数可以将它的实例标识为一种特定的类型。

 1.将构造函数当作函数

构造函数与其他函数的唯一区别,在于调用它们的方式不同。构造函数也是函数,所以不存在定义构造函数的特殊语法。任何函数,只要通过new操作符来调用,那它都可以作为构造函数;而任何函数,如果不通过new操作符来调用,那它跟普通函数没什么差别。举栗:

//当作构造函数使用
var person = new Person("Andy",28,"Actor");
person.sayName();        //"Andy"

//作为普通函数调用
Person("Lily",22,"Doctor")   //添加到window
window.sayName();       //"Lily"

//在另一个对象的作用域中调用
var o = new Object();
Person.call(o,"Joe",25,"Nurse");
o.sayName();          //"Joe"

以上前两行代码是构造函数的典型用法,就是用new操作符创建一个新的对象。

中间两行代码不用new操作符调用Person对象,属性和方法都被添加给了全局对象window。

最后两行代码使用call()(或者apply())在某个特殊对象的作用域中调用Person()函数,那么对象o就拥有了所有的属性和方法。

2.构造函数的问题

构造函数主要问题:每个方法都要在每个实例上重新创建一遍。

前面的栗子中,person1和person2都有一个名为sayName()的方法,但那连个方法不是同一个Function的实例。

ECMAScript中的函数是对象,因此每定义一个函数,就是实例化了一个对象。

从以上逻辑角度,此时的构造函数也可以这样定义。

 

function Person(name,age,job){
  this.name = name;
  this.age = age;
  this.job = job;
  this.sayName = new Function("console.log(this.name)"); //与声明函数在逻辑上是等价的        
}

 

 

参考资料

《javascript高级程序设计(第3版)》第6章 面向对象的程序设计

面向对象-读书笔记