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

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ī)理念, 對象應(yīng)該由一個公共的接口(類沟沙、函數(shù))來進行統(tǒng)一創(chuàng)建河劝,需要創(chuàng)建對象時,直接初始化某個類或者調(diào)用函數(shù)來進行創(chuàng)建矛紫。

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

工廠模式

工廠模式很簡單煎娇,對原料(原生 Object 對象)進行一些加工(參數(shù)),然后返回一個產(chǎn)品(被加工后的對象)贪染。

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

如果我們需要創(chuàng)建某個對象缓呛,只需調(diào)用相應(yīng)的工廠函數(shù):

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

工廠模式的缺點

工廠模式的解決了批量創(chuàng)建對象的問題,但也有一個明顯的缺點:沒有“類”的概念杭隙,除了能夠批量創(chuàng)建對象哟绊,無法對這些對象進行判斷,無法知道這些對象是由誰(類)創(chuàng)建出來的痰憎∑彼瑁基于這個問題,出現(xiàn)了構(gòu)造函數(shù)模式铣耘。

構(gòu)造函數(shù)模式

函數(shù)是 JavaScript 中的一等公民洽沟,可以做很多事情,其中有一項功能就是可以被 new 操作符調(diào)用蜗细。在 ES6 之前裆操,JavaScript 中是沒有 class 關(guān)鍵字的怒详,于是有了通過 new 操作符來調(diào)用函數(shù)創(chuàng)建一個對象的方式,很明顯踪区,通過 new 操作符調(diào)用的函數(shù)就是所謂的“類”昆烁。

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")

構(gòu)造函數(shù)中的 this 關(guān)鍵字就指向了當前被創(chuàng)建的對象。
通過這種方式創(chuàng)建對象以后缎岗,我們就可以知道對象是被哪個“類”創(chuàng)建的了静尼。

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

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

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

構(gòu)造函數(shù)創(chuàng)建對象的流程

使用構(gòu)造函數(shù)創(chuàng)建對象薪鹦,大概有如下幾個流程:

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

構(gòu)造函數(shù)作為函數(shù)

構(gòu)造函數(shù)本身也是函數(shù)池磁,因此其可以作為函數(shù)調(diào)用,由于構(gòu)造函數(shù)中使用 this 關(guān)鍵字楷兽,我們可以通過構(gòu)造函數(shù)為某個對象進行賦值地熄。this 為哪個對象賦值,決定于這個函數(shù)執(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"

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

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

這里明確指定函數(shù)的上下文為對象 o 后,調(diào)用 Person 函數(shù)就為 o 對象添加屬性方法了筛圆。

構(gòu)造函數(shù)模式的問題

使用構(gòu)造函數(shù)模式創(chuàng)建對象看起來是個不錯的方式裂明,但這樣有沒有缺陷呢?也是有的太援。這個缺陷就在于每次使用構(gòu)造函數(shù)創(chuàng)建對象時闽晦,都會為每個對象重新創(chuàng)建一份屬性和方法的副本,無法實現(xiàn)復(fù)用提岔。
為什么會這樣呢仙蛉?因為構(gòu)造函數(shù)本質(zhì)也是一個函數(shù),函數(shù)在運行時會有一個獨立的作用域碱蒙,創(chuàng)建多個對象時會多次調(diào)用構(gòu)造函數(shù)捅儒,并把這些函數(shù)的作用域賦值給對象,然后為對象添加屬性。但是這些函數(shù)的作用域是獨立的巧还,因此我們在構(gòu)造函數(shù)體內(nèi)所做的任何變量聲明鞭莽、函數(shù)聲明,都會在運行時重新創(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

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

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 方法就實現(xiàn)了代碼復(fù)用走孽,節(jié)約了資源惧辈。但這種方式也是有問題的:增加了全局變量,而且破壞了封裝性磕瓷。后面將會介紹更多創(chuàng)建對象的方法盒齿,一步步進行完善。

完困食。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末边翁,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子硕盹,更是在濱河造成了極大的恐慌符匾,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瘩例,死亡現(xiàn)場離奇詭異啊胶,居然都是意外死亡,警方通過查閱死者的電腦和手機垛贤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門创淡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人南吮,你說我怎么就攤上這事琳彩。” “怎么了部凑?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵露乏,是天一觀的道長。 經(jīng)常有香客問我涂邀,道長瘟仿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任比勉,我火速辦了婚禮劳较,結(jié)果婚禮上驹止,老公的妹妹穿的比我還像新娘。我一直安慰自己观蜗,他們只是感情好臊恋,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著墓捻,像睡著了一般抖仅。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上砖第,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天撤卢,我揣著相機與錄音,去河邊找鬼梧兼。 笑死放吩,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的羽杰。 我是一名探鬼主播渡紫,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼忽洛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起环肘,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤欲虚,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后悔雹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體复哆,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年腌零,在試婚紗的時候發(fā)現(xiàn)自己被綠了梯找。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡益涧,死狀恐怖锈锤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情闲询,我是刑警寧澤久免,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站扭弧,受9級特大地震影響阎姥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸽捻,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一呼巴、第九天 我趴在偏房一處隱蔽的房頂上張望泽腮。 院中可真熱鬧,春花似錦衣赶、人聲如沸诊赊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽豪筝。三九已至,卻和暖如春摘能,著一層夾襖步出監(jiān)牢的瞬間续崖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工团搞, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留严望,地道東北人。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓逻恐,卻偏偏與公主長得像像吻,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子复隆,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 普通創(chuàng)建對象和字面量創(chuàng)建對象不足之處:雖然 Object 構(gòu)造函數(shù)或?qū)ο笞置媪慷伎梢杂脕韯?chuàng)建單個對象拨匆,但這些方式有...
    believedream閱讀 2,377評論 2 18
  • 博客內(nèi)容:什么是面向?qū)ο鬄槭裁匆嫦驅(qū)ο竺嫦驅(qū)ο缶幊痰奶匦院驮瓌t理解對象屬性創(chuàng)建對象繼承 什么是面向?qū)ο?面向?qū)ο?..
    _Dot912閱讀 1,424評論 3 12
  • 設(shè)計模式匯總 一、基礎(chǔ)知識 1. 設(shè)計模式概述 定義:設(shè)計模式(Design Pattern)是一套被反復(fù)使用挽拂、多...
    MinoyJet閱讀 3,947評論 1 15
  • 于2017年四月份加入實驗室學習中惭每,以下是我對實驗室管理方面的一些建議,可能不太成熟亏栈,望指點台腥。 學習管理1 發(fā)布學...
    QinRenMin閱讀 688評論 2 0
  • 做夢的時候,清清楚楚知道自己正在做夢绒北,也有些人剛好相反黎侈,以為自己醒來,其實還在做夢闷游。
    大方demi閱讀 237評論 1 2