工廠模式,構造器模式和原型模式

1、工廠模式

工廠模式屬於建立型模式,它提供了一種建立對象的最佳方式。咱們在函數內部建立一個對象,賦予對象屬性和方法,並經過return返回這個對象數組

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('caoyuan', 25, 'Software engineer')
  var person2 = createPerson('neil', 23, 'Software engineer')
  console.log(person1) // {name: "caoyuan", age: 25, job: "Software engineer", sayName: ƒ}
  console.log(person2) // {name: "neil", age: 23, job: "Software engineer", sayName: ƒ}
複製代碼

2、構造函數模式

構造模式和工廠模式建立對象的不一樣點在於;安全

  1. 沒有顯式的建立對象
  2. 直接將屬性和方法賦值給了this對象
  3. 沒有return對象
function Person(name, age, job) {
    this.name = name
    this.age = age
    this.job = job
    this.sayName = function() {
      console.log(this.name)
    }
  }
  let person1 = new Person('caoyuan', 25, 'Software Engineer')
  let person2 = new Person('neil', 23, 'Software engineer')
  person1.sayName()
  person2.sayName()
複製代碼

以這種方式調用構造函數實際會經歷一下四個步驟markdown

  1. 建立一個對象
  2. 將構造函數的做用域賦給新對象(所以this就指向這個對象)
  3. 執行構造函數種的代碼(爲這個新對象添加屬性)
  4. 返回對象

寄生構造函模式

這種模式的基本思想是建立一個函數,該函數的做用僅僅是封裝對象的代碼,而後再返回新建立的對象。app

function Person(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
  }
  let friend = new Person('neil', 25, 'software Engineer')
  friend.sayName() // neil
複製代碼

以上就是例子,把new操做符拋去,這個模式和工廠模式如出一轍。構造函數在不返回值的狀況下,默認會返回新對象實例,而經過構造函數的末尾添加一個return語句,能夠重寫調用給構造函數時返回的值。 以下例子ide

function SpecialArray () {
    // 建立數組
    var values = new Array()
    // 添加值
    values.push.apply(values, arguments)
    // 添加方法
    values.toPipedString = function() {
      return this.join('|')
    }

    // 返回數組
    return values

  }
  var color = new SpecialArray('1','2','3')
  console.log(color.toPipedString()) // 1|2|3
複製代碼

穩妥構造函數模式 穩妥對象是指沒有公共屬性, 方法也不引用this的對象。適合在安全的環境中,或者防止數據被其餘應該改動時使用函數

穩妥模式遵循與寄生構造函數相似的模式,但 有兩點不一樣;post

  1. 建立新對象的實例不引用this;
  2. 不使用new操做符調用構造函數
function Person(name, age, job) {
    var o = new Object()
    o.sayName = function() {
      console.log(name)
    }
    return o
  }

  let person = Person('neil', 25, 'software Engineer')
  person.sayName() // neil
複製代碼

做用域安全的構造函數

經過代碼介紹下做用域安全的構造函數
function Person(name, age, job) {
    this.name = name
    this.age = age
    this.job = job
  }
 var person = Person('neil', 25, 'Softwate Engineer')
 console.log(window.age) // 25

複製代碼

假設用上述這種方式調用,this指向window,那麼值也就在window上了,那麼怎麼才能解決這種問題呢, 修改代碼以下ui

function Person(name, age, job) {
    if (this instanceof Person) {
      this.name = name
      this.age = age
      this.job = job
    } else {
      return new Person(name, age, job)
    }
  }
  var person = Person('neil', 25, 'software Engineer')
  console.log(window.age) // undefined
  console.log(person.age) // 25
複製代碼

經過instanceof來判斷當前this是不是person實例上的,如今看上去好像沒有什麼問題了,那麼假設用了構造函數竊取模式的繼承且不使用原型鏈,這個繼承可能就被破壞了this

function Polygon(sides) {
    if (this instanceof Polygon) {
      this.sides = sides
      this.getArea = function() {
        return 0
      }
    } else {
      return new Polygon(sides)
    }
  }

  function Rectangle(width, heigth) {
    Polygon.call(this, 2) 
    this.width = width
    this.heigth = heigth
    this.getArea = function () {
      return this.width * this.heigth
    }
  }
  let rect = new Rectangle(5, 10)
  console.log(rect.sides) // undefined

複製代碼

你會發現,rect.sides爲undefined,爲啥呢,Polygon這個實例是安全的,可是,Rectangle中是經過call來繼承Polygon的sides屬性,這是由於this對象不是Polygon的實例,因此建立了一個新的Polygon對象,Rectangle中並無sides屬性。若是構造函數竊取結合使用原型鏈和寄生模式就能夠解決這個問題了,代碼以下spa

function Polygon(sides) {
    if (this instanceof Polygon) {
      this.sides = sides
      this.getArea = function() {
        return 0
      }
    } else {
      return new Polygon(sides)
    }
  }

  function Rectangle(width, heigth) {
    Polygon.call(this, 2) 
    this.width = width
    this.heigth = heigth
    this.getArea = function () {
      return this.width * this.heigth
    }
  }
  Rectangle.prototype = new Polygon()
  let rect = new Rectangle(5, 10)
  console.log(rect.sides) // 2
複製代碼

3、原型模式

咱們建立的每一個函數都有prototype屬性,這個屬性是一個指針,指向對象,而這個對象包含能夠由特定類型的全部實列共享的屬性和方法。prototype就是經過調用構造函數而建立的那個實例對象的原型對象。

function Person() {
  }
  Person.prototype.name = 'caoyuan'
  Person.prototype.age = '25'
  Person.prototype.sayName = function() {
    console.log(this.name)
  }
  let person1 = new Person()
  let person2 = new Person()
  person2.sayName()
  person1.sayName()
  console.log(person1.sayName == person2.sayName)

複製代碼

動態原型模式

它把全部信息都封裝在了構造函數中,而經過在構造函數中初始化原型,也保持了同時使用構造函數和原型的優勢

function Person(name, age, job) {
    this.name = name
    this.age = age
    this.job = job
    // 方法
    if (typeof this.sayName != 'function') {
      Person.prototype.sayName = function() {
        console.log(this.name)
      }
    }
  }
  let person = new Person('neil', 25, 'Software Engineer')
  person.sayName()

複製代碼

4、組合使用構造函數模式和原型模式

建立自定義對象最多見的方式,就是組合使用構造函數模式和原型模式。

  1. 構造函數模式定義實例的屬性
  2. 原型模式用於定義方法和共享的屬性
function Person(name, age, job) {
  this.name = name
  this.age = age
  this.children = ['1', '2']
}
Person.prototype.sayName = function() {
  console.log(this.name)
}

let person1 = new Person('caoyuan', 25, 'Software Engineer')
let person2 = new Person('neil', 23, 'Software Engineer')

person1.children.push('3')
console.log(person1.children) // Array [1,2,3]
console.log(person2.children) // Array [1,2]
console.log(person1.children === person2.children) // false
console.log(person1.sayName === person2.sayName) // true
複製代碼

相關文章:

原型鏈基礎及多種使用方式

相關文章
相關標籤/搜索