004 創(chuàng)建對象之工廠模式和構造函數模式

JavaScript 中創(chuàng)建對象的方式有很多,比如對象字面量模式或者使用 Object 創(chuàng)建:

// 創(chuàng)建 obj1 對象
let obj1 = {
  name:"",
  showName(){ return this.name }
}

// 創(chuàng)建 obj2 對象
let obj2 = new Object()
obj2.name = ""
obj2.showName = function(){ return this.name }

使用這兩種方式(特別是對象字面量方式)創(chuàng)建對象十分方便,可以拿來即用。但也有一些缺點:

  • 過程過于繁瑣,如果需要創(chuàng)建多個對象,就需要書寫多次創(chuàng)建代碼
  • 封裝性不夠,因為按照常規(guī)理念, 對象應該由一個公共的接口(類、函數)來進行統一創(chuàng)建,需要創(chuàng)建對象時,直接初始化某個類或者調用函數來進行創(chuàng)建。

上面的兩個缺陷都指向了一點:我們需要一個函數(類)來進行對象創(chuàng)建,基于這個理念,出現了使用工廠模式來創(chuàng)建對象的方式。

工廠模式

工廠模式很簡單,對原料(原生 Object 對象)進行一些加工(參數),然后返回一個產品(被加工后的對象)。

function createPerson(name,age){
  // 創(chuàng)建一個原生對象
  let o = new Object()
  o.name = name;
  o.age = age
  return o;
}

如果我們需要創(chuàng)建某個對象,只需調用相應的工廠函數:

let p1 = createPerson("MIKE",20)
let p2 = createPerson("JACK",22)

工廠模式的缺點

工廠模式的解決了批量創(chuàng)建對象的問題,但也有一個明顯的缺點:沒有“類”的概念,除了能夠批量創(chuàng)建對象,無法對這些對象進行判斷,無法知道這些對象是由誰(類)創(chuàng)建出來的?;谶@個問題,出現了構造函數模式。

構造函數模式

函數是 JavaScript 中的一等公民,可以做很多事情,其中有一項功能就是可以被 new 操作符調用。在 ES6 之前,JavaScript 中是沒有 class 關鍵字的,于是有了通過 new 操作符來調用函數創(chuàng)建一個對象的方式,很明顯,通過 new 操作符調用的函數就是所謂的“類”。

function Person(name,age){
  this.name = name;
  this.age = age;
  this.intro = function(){
    console.log(`name:${this.name},age:${this.age}`)
  }
}

接下來通過 Person 類來創(chuàng)建對象:

let p1 = new Person("MIKE",20)
let p2 = new Person("JACK","22")

構造函數中的 this 關鍵字就指向了當前被創(chuàng)建的對象。
通過這種方式創(chuàng)建對象以后,我們就可以知道對象是被哪個“類”創(chuàng)建的了。

p1 instanceof Person //true
p1 instanceof Object //true
p1.constructor === Person //true

當對象被創(chuàng)建后,其會擁有一個 constructor 屬性,指向其的構造函數。不過由于 JavaScript 太靈活了,constructor 屬性是可以被修改的,因此通過 constructor 來對對象的類進行判斷是不準確的,使用
instanceof 操作符更加可靠。

p1.constructor = Array
p1.constructor // Array
p1.constructor === Person //false
p1 instanceof Person // true

構造函數創(chuàng)建對象的流程

使用構造函數創(chuàng)建對象,大概有如下幾個流程:

  • 創(chuàng)建一個新對象
  • 將構造函數的作用域賦值給這個對象(因此 this 就指向了這個對象)
  • 執(zhí)行構造函數中的代碼,為對象添加屬性方法
  • 函數執(zhí)行完畢,對象被銷毀

構造函數作為函數

構造函數本身也是函數,因此其可以作為函數調用,由于構造函數中使用 this 關鍵字,我們可以通過構造函數為某個對象進行賦值。this 為哪個對象賦值,決定于這個函數執(zhí)行時的上下文。

function Person(name,age){
  this.name = name;
  this.age = age;
  this.intro = function(){
    console.log(`name:${this.name},age:${this.age}`)
  }
}

let p1 = Person("MIKE","20")
p1 //undefined
window.name //"MIKE"
window.age //"20"

如果不指定函數的上下文,默認為 window 對象,因此 Person 函數執(zhí)行時,為 window 對象添加了屬性和方法。

let o = {}
Person.call(o,"JACK","22")
o //{name:"JACK",age:"22"}

這里明確指定函數的上下文為對象 o 后,調用 Person 函數就為 o 對象添加屬性方法了。

構造函數模式的問題

使用構造函數模式創(chuàng)建對象看起來是個不錯的方式,但這樣有沒有缺陷呢?也是有的。這個缺陷就在于每次使用構造函數創(chuàng)建對象時,都會為每個對象重新創(chuàng)建一份屬性和方法的副本,無法實現復用。
為什么會這樣呢?因為構造函數本質也是一個函數,函數在運行時會有一個獨立的作用域,創(chuàng)建多個對象時會多次調用構造函數,并把這些函數的作用域賦值給對象,然后為對象添加屬性。但是這些函數的作用域是獨立的,因此我們在構造函數體內所做的任何變量聲明、函數聲明,都會在運行時重新創(chuàng)建一次,然后添加到對象上。

function Person(name,age){
  this.name = name;
  this.age = age;
  this.intro = function(){
    console.log(`name:${this.name},age:${this.age}`)
  }
}

let p1 = new Person("MIKE","20")
let p2 = new Person("JACK","22")
p1.intro === p2.intro // false

以上就是使用構造函數創(chuàng)建對象無法實現復用的原因,既然無法復用的原因是由于在獨立作用于中創(chuàng)建變量和函數,那我們把這些變量和函數放到函數的獨立作用于之外不就可以了?確實如此。

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

function intro(){
  console.log(`name:${this.name},age:${this.age}`)
}


let p1 = new Person("MIKE","20")
let p2 = new Person("JACK","22")
p1.intro === p2.intro // true

上面的 intro 方法就實現了代碼復用,節(jié)約了資源。但這種方式也是有問題的:增加了全局變量,而且破壞了封裝性。后面將會介紹更多創(chuàng)建對象的方法,一步步進行完善。

完。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 普通創(chuàng)建對象和字面量創(chuàng)建對象不足之處:雖然 Object 構造函數或對象字面量都可以用來創(chuàng)建單個對象,但這些方式有...
    believedream閱讀 2,580評論 2 18
  • 博客內容:什么是面向對象為什么要面向對象面向對象編程的特性和原則理解對象屬性創(chuàng)建對象繼承 什么是面向對象 面向對象...
    _Dot912閱讀 1,535評論 3 12
  • 設計模式匯總 一、基礎知識 1. 設計模式概述 定義:設計模式(Design Pattern)是一套被反復使用、多...
    MinoyJet閱讀 4,093評論 1 15
  • 于2017年四月份加入實驗室學習中,以下是我對實驗室管理方面的一些建議,可能不太成熟,望指點。 學習管理1 發(fā)布學...
    QinRenMin閱讀 767評論 2 0
  • 做夢的時候,清清楚楚知道自己正在做夢,也有些人剛好相反,以為自己醒來,其實還在做夢。
    大方demi閱讀 281評論 1 2

友情鏈接更多精彩內容