JavaScript中工廠函數(shù)與構(gòu)造函數(shù)示例詳解
前言
當(dāng)談到JavaScript語(yǔ)言與其他編程語(yǔ)言相比時(shí),你可能會(huì)聽到一些令人困惑東西,其中之一是工廠函數(shù)和構(gòu)造函數(shù)。
工廠函數(shù)
所謂工廠函數(shù),就是指這些內(nèi)建函數(shù)都是類對(duì)象,當(dāng)你調(diào)用他們時(shí),實(shí)際上是創(chuàng)建了一個(gè)類實(shí)例”。意思就是當(dāng)我調(diào)用這個(gè)函數(shù),實(shí)際上是先利用類創(chuàng)建了一個(gè)對(duì)象,然后返回這個(gè)對(duì)象。由于 Javascript 本身不是嚴(yán)格的面向?qū)ο蟮恼Z(yǔ)言(不包含類),實(shí)際上來(lái)說(shuō),Javascript 并沒有嚴(yán)格的“工廠函數(shù)”,但是在 Javascript中,我們能利用函數(shù)模擬類。來(lái)看下面一個(gè)例子:
function person(firstName, lastName, age) {
const person = {};
person.firstName = firstName;
person.lastName = lastName;
person.age = age;
return person;
}
上述代碼,創(chuàng)建一個(gè)新對(duì)象,并將傳遞參數(shù)作為屬性附加到該對(duì)象上并返回新對(duì)象。 這是一個(gè)簡(jiǎn)單的 JavaScript 工廠函數(shù)。
實(shí)際上工廠函數(shù)也很好理解了:
- 它是一個(gè)函數(shù)。
- 它用來(lái)創(chuàng)建對(duì)象。
- 它像工廠一樣,“生產(chǎn)”出來(lái)的函數(shù)都是“標(biāo)準(zhǔn)件”(擁有同樣的屬性)
構(gòu)造函數(shù)
不同于其它的主流編程語(yǔ)言,JavaScript的構(gòu)造函數(shù)并不是作為類的一個(gè)特定方法存在的;當(dāng)任意一個(gè)普通函數(shù)用于創(chuàng)建一類對(duì)象時(shí),它就被稱作構(gòu)造函數(shù),或構(gòu)造器。一個(gè)函數(shù)要作為一個(gè)真正意義上的構(gòu)造函數(shù),需要滿足下列條件:
- 在函數(shù)內(nèi)部對(duì)新對(duì)象(this)的屬性進(jìn)行設(shè)置,通常是添加屬性和方法。
- 構(gòu)造函數(shù)可以包含返回語(yǔ)句(不推薦),但返回值必須是this,或者其它非對(duì)象類型的值。
function Person(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
使用 new 關(guān)鍵字創(chuàng)建對(duì)象
正如上面所說(shuō)的,我們可以使用 new 來(lái)類或者對(duì)象,那么你可能會(huì)有以下幾個(gè)問(wèn)題:
- 我們可以在工廠函數(shù)中使用 new 關(guān)鍵字嗎?
- 如果我們?cè)诠S和構(gòu)造函數(shù)中使用new關(guān)鍵字會(huì)發(fā)生什么
- 如果在使用構(gòu)造函數(shù)創(chuàng)建對(duì)象實(shí)例時(shí)不使用new關(guān)鍵字會(huì)發(fā)生什么
好的,試著找出以上問(wèn)題的答案之前,我們先做一個(gè)小練習(xí)來(lái)理解這里面發(fā)生了什么。
使用new關(guān)鍵字同時(shí)使用工廠和構(gòu)造函數(shù)創(chuàng)建兩個(gè)對(duì)象,接著在控制臺(tái)打印這兩個(gè)對(duì)象。
使用工廠函數(shù)
function person(firstName, lastName, age){
const person = {}
person.firstName = firstName;
person.lastName = lastName;
person.age = age;
return person;
}
const mike = new person('mike', 'grand', 23);

正如我們?cè)谏鲜鏊吹降?,這里的__proto__ 指向其原型對(duì)象的指針,讓我們?cè)囍页鲈蛯?duì)象是什么。為了找出上面mike對(duì)象的指向原型對(duì)象,讓我們做簡(jiǎn)單的===等式檢查。

嗯,有趣的是,它指向 Object.prototype。好的,讓我們用構(gòu)造函數(shù)做同樣的實(shí)驗(yàn)。
理解 JavaScript 的原型
理解原型之前,需要記住以下幾點(diǎn)知識(shí):
- 所有的引用類型(數(shù)組、對(duì)象、函數(shù)),都具有對(duì)象特性,即可自由擴(kuò)展屬性(null除外)
- 所有的引用類型(數(shù)組、對(duì)象、函數(shù)),都有一個(gè)__proto__屬性,屬性值是一個(gè)普通的對(duì)象
- 所有的函數(shù),都有一個(gè)prototype屬性,屬性值也是一個(gè)普通的對(duì)象
- 所有的引用類型(數(shù)組、對(duì)象、函數(shù)),__proto__屬性值指向它的構(gòu)造函數(shù)的prototype屬性值
通過(guò)代碼解釋一下:
// 要點(diǎn)一:自由擴(kuò)展屬性
var obj = {}; obj.a = 100;
var arr = []; arr.a = 100;
function fn () {}
fn.a = 100;
// 要點(diǎn)二:__proto__
console.log(obj.__proto__);
console.log(arr.__proto__);
console.log(fn.__proto__);
// 要點(diǎn)三:函數(shù)有 prototype
console.log(fn.prototype)
// 要點(diǎn)四:引用類型的 __proto__ 屬性值指向它的構(gòu)造函數(shù)的 prototype 屬性值
console.log(obj.__proto__ === Object.prototype)
使用構(gòu)造函數(shù)
注意:在JavaScript中,這些構(gòu)造函數(shù)也被稱為 constructor,因?yàn)樗鼈冇糜趧?chuàng)建對(duì)象。
function Person(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
const mike = new Person('mike', 'grand', 23);

當(dāng)我們展開第一層的的__proto__時(shí),它內(nèi)部還有另一個(gè)__proto__,我們?cè)俅螖U(kuò)展它。

現(xiàn)在讓我們?cè)囍宄蛯?duì)象是否像上面一樣。

他們是不同的。 當(dāng)我們使用工廠函數(shù)創(chuàng)建對(duì)象時(shí),它的__proto__指向Object.prototype,而當(dāng)從構(gòu)造函數(shù)創(chuàng)建對(duì)象時(shí),它指向它的構(gòu)造函數(shù)原型對(duì)象。 那么這里發(fā)生了什么?
new 背后所做的事
當(dāng)我們?cè)趧?chuàng)建對(duì)象時(shí)使用帶有構(gòu)造函數(shù)的new關(guān)鍵字時(shí),new 背后所做的事不多。
new 運(yùn)算符創(chuàng)建一個(gè)用戶自定義的對(duì)象類型的實(shí)例或具有構(gòu)造函數(shù)的內(nèi)置對(duì)象的實(shí)例。 new 關(guān)鍵字會(huì)進(jìn)行如下操作:
- 創(chuàng)建一個(gè)空的簡(jiǎn)單 JavaScript 對(duì)象 (即 {})
- 鏈接該對(duì)象(即設(shè)置該對(duì)象的構(gòu)造函數(shù))到另一個(gè)對(duì)象
- 將步驟1新創(chuàng)建的對(duì)象作為 this 的上下文
- 如果該函數(shù)沒有返回對(duì)象,則返回 this
注釋行是偽代碼,表示在 new 關(guān)鍵字,JS 背后幫我們做的事情。
function Person(firstName, lastName, age) {
// this = {};
// this.__proto__ = Person.prototype;
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
// return this;
}
另外,讓我們看看如果將上面的隱式代碼添加到工廠函數(shù)中會(huì)發(fā)生什么。
function person(firstName, lastName, age) {
// this = {};
// this.__proto__ = Person.prototype;
const person = {};
person.firstName = firstName;
person.lastName = lastName;
person.age = age;
return person;
// return this;
}
即使使用new關(guān)鍵字調(diào)用時(shí)將隱式代碼添加到工廠函數(shù)中,也不會(huì)對(duì)結(jié)果產(chǎn)生任何影響。這是因?yàn)椋捎谖覀儧]有在函數(shù)中使用 this 關(guān)鍵字,而且我們顯式地返回了一個(gè)除this之外的自定義對(duì)象,因此沒有必要使用隱式代碼。無(wú)論我們是否對(duì)工廠函數(shù)使用new關(guān)鍵字,對(duì)輸出都沒有影響。
如果忘記了 new 關(guān)鍵字怎么辦
JavaScript 中有許多概念,有時(shí)難以掌握。 new 操作符就是其中之一。 如果你不能正確理解它,那么在運(yùn)行 JavaScript 應(yīng)用程序時(shí)會(huì)產(chǎn)生令人討厭的后果。 在像 Java這 樣的語(yǔ)言中,嚴(yán)格限制了如何使用 new 關(guān)鍵字。 但是在 javascript 中,并不是那么嚴(yán)格,如果你不能正確理解它們可能會(huì)導(dǎo)致很多問(wèn)題。
在 JavaScript 中:
- 可以對(duì)任何函數(shù)使用 new 運(yùn)算符
- 可以使用或不使用 new 關(guān)鍵字將函數(shù)作為構(gòu)造函數(shù)調(diào)用
讓我們看看上面的例子,使用和不使用 new 關(guān)鍵情況
function Person(firstName, lastName, age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
const mike = new Person('mike', 'grand', 23);
const bob = Person('bob', 'grand', 23);
然后,如果查看創(chuàng)建的對(duì)象實(shí)例,你希望看到什么?

發(fā)生了什么? 使用 new 運(yùn)算符,正如我們所期待的一樣輸出正確的對(duì)象,但沒有new運(yùn)算符,結(jié)果是undefined 怎么可能呢?
如果你對(duì) JavaScript 作用域 和 this 關(guān)鍵字的工作原理有所了解,那么你可以猜到這里發(fā)生了什么? 讓我們來(lái)看看。

看起來(lái)我們傳遞給沒有new關(guān)鍵字的函數(shù)的所有屬性都已設(shè)置為window對(duì)象。 那是因?yàn)榈侥莻€(gè)時(shí)候函數(shù)內(nèi)部的這個(gè)變量引用了global 或 window 對(duì)象,基本上我們?cè)谶@里做的就是污染了全局對(duì)象。
這是你可以對(duì)你的JavaScript程序做的非常討厭的事情。 因此,使用new運(yùn)算符,JavaScript引擎將this 變量設(shè)置為引用新創(chuàng)建的對(duì)象實(shí)例,這就是為什么我們可以看到傳遞給構(gòu)造函數(shù)的所有屬性都已設(shè)置為 mike。
但是在沒有new運(yùn)算符的情況下調(diào)用構(gòu)造函數(shù)的情況下,JavaScript 引擎會(huì)將 this 解釋為常規(guī)函數(shù)調(diào)用,而沒有顯式返回語(yǔ)句時(shí)返回undefined。 這就是理解new 運(yùn)算符在JavaScript中的工作原理非常關(guān)鍵的原因。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
- JavaScript對(duì)象字面量和構(gòu)造函數(shù)原理與用法詳解
- JavaScript如何借用構(gòu)造函數(shù)繼承
- js核心基礎(chǔ)之構(gòu)造函數(shù)constructor用法實(shí)例分析
- 深入淺析js原型鏈和vue構(gòu)造函數(shù)
- JavaScript原型對(duì)象、構(gòu)造函數(shù)和實(shí)例對(duì)象功能與用法詳解
- js構(gòu)造函數(shù)創(chuàng)建對(duì)象是否加new問(wèn)題
- 詳解Javascript 中的 class、構(gòu)造函數(shù)、工廠函數(shù)
- JavaScript構(gòu)造函數(shù)原理及實(shí)現(xiàn)流程解析
相關(guān)文章
JS實(shí)現(xiàn)統(tǒng)計(jì)字符串中字符出現(xiàn)個(gè)數(shù)及最大個(gè)數(shù)功能示例
這篇文章主要介紹了JS實(shí)現(xiàn)統(tǒng)計(jì)字符串中字符出現(xiàn)個(gè)數(shù)及最大個(gè)數(shù)功能,結(jié)合實(shí)例形式分析了javascript字符串遍歷、統(tǒng)計(jì)相關(guān)操作技巧,需要的朋友可以參考下2018-06-06
怎樣用Javascript實(shí)現(xiàn)建造者模式
這篇文章主要介紹了怎樣用Javascript實(shí)現(xiàn)建造者模式,想學(xué)習(xí)設(shè)計(jì)模式的同學(xué),可以參考下2021-04-04
JavaScript運(yùn)動(dòng)框架 解決速度正負(fù)取整問(wèn)題(一)
這篇文章主要為大家詳細(xì)介紹了JavaScript運(yùn)動(dòng)框架的第一部分,解決速度正負(fù)取整問(wèn)題,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
js基于canvas實(shí)現(xiàn)時(shí)鐘組件
這篇文章主要介紹了js基于canvas實(shí)現(xiàn)時(shí)鐘組件的方法,幫助大家更好的理解和使用JavaScript,感興趣的朋友可以了解下2021-02-02
微信小程序中webview組件的使用與應(yīng)用場(chǎng)景詳解
web-view組件是一個(gè)可以用來(lái)承載網(wǎng)頁(yè)的容器,會(huì)自動(dòng)鋪滿整個(gè)小程序頁(yè)面,這篇文章主要介紹了微信小程序中的webview組件的基本使用方法、應(yīng)用場(chǎng)景、通信機(jī)制以及注意事項(xiàng),需要的朋友可以參考下2025-03-03
JavaScript尾遞歸的實(shí)現(xiàn)及應(yīng)用場(chǎng)景
本文主要介紹了JavaScript尾遞歸的實(shí)現(xiàn)及應(yīng)用場(chǎng)景,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05
javascript利用控件對(duì)windows的操作實(shí)現(xiàn)原理與應(yīng)用
假如要發(fā)送漢字的聊天框的內(nèi)容的話,我們也要從windows消息機(jī)制下手,先找到聊天消息的句柄(可以利用findwindow函數(shù)或者用spy工具哈),然后在找到上面的聊天框的句柄,接著我們就可以想這個(gè)句柄發(fā)送WM_SETTEXT的消息了2012-12-12
JavaScript 數(shù)組的進(jìn)化與性能分析
這篇文章主要介紹了JavaScript 數(shù)組的進(jìn)化與性能分析,本文講得更多的是內(nèi)存、優(yōu)化、語(yǔ)法差異、性能、近來(lái)的演進(jìn)。需要的朋友可以參考下2017-09-09

