1.工厂模式


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 p1 = createPerson('李四', 18, '程序员')
  var p2 = createPerson('张三', 20, '产品经理')

问题:无法识别对象的类型

2.构造函数模式

 

function Person(name,age,job){
    this.name = name
    this.age = age
    this.job = job 
    this.sayName = function(){
      alert(this.name)
    }
  }
  var p1 = new Person('李四', 18, '程序员')
  var p2 = new Person('张三', 20, '产品经理')

 

使用new操作符,创建实例经历下面四个过程:

1,创建一个新对象;

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

3,执行构造函数中的代码(为这个对象添加属性与方法);

4,返回这个新对象。

创建的对象p1和p2都有一个constructor属性,该属性都指向Person

p1.constructor === p2.constructor //true

往往我们通过instanceof来检测创建实例的类型

p1 instanceof Object //true
p1 instanceof Person //true
p2 instanceof Object //true
p2 instanceof Person //true

优点:可以识别创建实例的类型

缺点:构造函数中的方法在创建每一个实例中都会被重新创建

3.原型模式

我们创建的每一个函数都有一个prototype(原型)属性,该属性指向一个包含这个函数创建的所有实例共享的属性和方法的对象(原型对象),该原型对象有一个constructor(构造函数)属性,此属性指向该原型对象所在的构造函数,当调用该构造函数创建实例后,新生成的实例对象有一个[prototype]属性指向原型对象。

 

function Person(){

  }
  Person.prototype.name = '张三'
  Person.prototype.age = 18
  Person.prototype.job = '程序员'
  Person.prototype.sayName = function(){
    alert(this.name)
  }
  var p1 = new Person()

 

isPrototypeOf() 确定实例和原型对象之间的关系是否建立

Person.prototype.isPrototypeOf(p1)  // true

Object().getPrototypeOf()获取实例的[prototype]

Object.getPrototypeOf(p1) === Person.prototype //true

虽然可以通过实例对象访问原型对象中的值,但是却无法通过实例对象重写原型对象中的值,当我们修改实例对象中原型对象重名的属性值时,就会在该实例中创建这个属性,该属性会屏蔽原型对象中的那个属性值。每当读取某个对象中的属性值时,都会执行一边搜索,先在该实例中搜索是否存在该属性,若有则返回该属性的值,若无,则继续在该实例对应的原型对象中搜索该属性。

hasOwnProperty()判断一个属性是存在实例还是存在原型对象中

 

p1.hasOwnProperty('name') //false
p1.name = '李四'
p1.hasOwnProperty('name') //true
delete p1.name
p1.hasOwnProperty('name') //false

 

更简单的原型语法

function Person(){

  }
  Person.prototype = {
    name: '张三',
    age: 18,
    job: '程序员',
    sayName: function(){
      alert(this.name)
    }
  }

以对象字面量的形式,给原型对象添加属性和方法,相当于重写默认的prototype,这样做后,会改变原型对象的constructor属性值,此时原型对象的constructor不再指向构造函数Person了,而是指向Object()构造函数。

问题:由于原型对象属性和方法的共享性,我们定义原型对象的某个属性值为引用类型,当我们在某个实例中修改该属性值会导致其他实例的属性值也随之改变。

4.组合模式

这是创建自定义类最常见的模式,采用构造函数定义实例属性,原型模式创建可共享的属性和方法,此举实现了每一个实例都有一份独立的属性副本,又避免了方法的重复创建,最大限度的节省了内存,而且这种模式还支持向构造函数传递参数。

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

  Person.prototype = {
    constructor: Person,
    sayName: function(){
      alert(this.name)
    }
  }

  var p1 = new Person('张三', 18, '程序员')
5.动态原型模式

将所有的信息都封装在构造函数中,在构造函数中初始化原型,这样只有在初次调用此构造函数时才会执行初始化原型的方法。

//动态原型模式
function Person (name,age,job){
  this.name = name
  this.job = job
  this.age = age
  if(typeof this.sayName != 'function'){
    Person.prototype.sayName = function(){
      alert(this.name)
    }
  }
}
var p1 = new Person('张三', 18, '程序员')
6.寄生构造函数模式
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 p1 = new CreatePerson('李四', 18, '程序员')

除了创建实例时使用new操作符以外和工厂模式没有区别,

7.稳妥构造函数模式
function CreatePerson(name,age,job){
    var o = new Object()
    o.name = name
    o.age = age
    o.job = job
    o.sayName = function(){
      alert(name)
    }
    return o
  }
  var p1 = CreatePerson('李四', 18, '程序员')