您好,登錄后才能下訂單哦!
在學(xué)習(xí)jQuery的時(shí)候,我們經(jīng)常會(huì)看到“工廠函數(shù)”這個(gè)概念,那么究竟什么是“工廠函數(shù)”呢?我們來(lái)看看概念,“所謂工廠函數(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ù)模擬類。
我們首先通過(guò)new關(guān)鍵字創(chuàng)建了一個(gè)對(duì)象,obj就相當(dāng)于Object的實(shí)例。我們通過(guò)類實(shí)例化了一個(gè)對(duì)象,然后給這個(gè)對(duì)象相應(yīng)的屬性,最后返回對(duì)象。我們可以通過(guò)調(diào)用這個(gè)函數(shù)來(lái)創(chuàng)建對(duì)象,這樣的話,實(shí)際上工廠函數(shù)也很好理解了:
1,它是一個(gè)函數(shù)。
2,它用來(lái)創(chuàng)建對(duì)象。
3,它像工廠一樣,“生產(chǎn)”出來(lái)的函數(shù)都是“標(biāo)準(zhǔn)件”(擁有同樣的屬性)
不學(xué)習(xí)函數(shù)和對(duì)象,你不可能成為一名JavaScript程序員,并且當(dāng)他們一起使用時(shí),是構(gòu)建塊,我們需要從一個(gè)稱為 組合(composition) 的強(qiáng)大對(duì)象范例開始。今天我們來(lái)看一些慣用的模式,使用工廠函數(shù)來(lái)組成函數(shù),對(duì)象和 Promises 。組合模式是將一批子對(duì)象組織為樹形結(jié)構(gòu),一條頂層的命令會(huì)在操作樹中所有的對(duì)象。當(dāng)一個(gè)函數(shù)返回一個(gè)對(duì)象時(shí),我們稱之他為 工廠函數(shù)(factory function) 。
讓我們來(lái)看一個(gè)簡(jiǎn)單的例子。
function createJelly() { return { type: 'jelly', colour: 'red' scoops: 3 }; }
下面我們通過(guò)一些實(shí)例給大家介紹。
每次我們調(diào)用這個(gè)工廠函數(shù),它將返回一個(gè)新的 jelly(果凍) 對(duì)象實(shí)例。要注意的重點(diǎn)是,我們不必在工廠函數(shù)名稱前面加上 create ,但它可以讓其他人更清楚函數(shù)的意圖。對(duì)于 type 屬性也是如此,但通常它可以幫助我們區(qū)分我們程序的對(duì)象。
1.帶參數(shù)的工廠函數(shù)
像所有函數(shù)一樣,我們可以通過(guò)參數(shù)來(lái)定義我們的工廠函數(shù) (icecream 冰淇淋),這可以用來(lái)改變返回對(duì)象的模型。
function createIceCream(flavour='Vanilla') { return { type: 'icecream', scoops: 3, flavour } }
理論上,您可以使用帶有數(shù)百個(gè)參數(shù)的工廠函數(shù)來(lái)返回非常特使的深層嵌套對(duì)象,但正如我們將看到的,這根本不是組合的精髓。
2.組合的工廠函數(shù)
在一個(gè)工廠函數(shù)中定義另一個(gè)工廠函數(shù),可以幫助我們把復(fù)雜的工廠函數(shù)拆分成更小的,可重用的碎片。
例如,我們可以創(chuàng)建一個(gè) dessert(甜點(diǎn))工廠函數(shù),通過(guò)前面的 jelly(果凍)和 icecream(冰淇淋)工廠函數(shù)來(lái)定義。
function createDessert() { return { type: 'dessert', bowl: [ createJelly(), createIceCream() ] }; }
我們可以組合工廠函數(shù)來(lái)構(gòu)建任意復(fù)雜的對(duì)象,這不需要我們結(jié)合使用 new 或 this 。對(duì)象可以用 has-a (具有) 關(guān)系而不是 is-a (是) 來(lái)表示。也就是說(shuō),可以用組合而不是繼承來(lái)實(shí)現(xiàn)。
例如,使用繼承。
// A trifle *is a* dessert 蛋糕*是*甜點(diǎn) function Trifle() { Dessert.apply(this, arguments); } Trifle.prototype = Dessert.prototype; // 或者 class Trifle extends Dessert { constructor() { super(); } }
我們可以用組合模式表達(dá)相同的意思。
// A trifle *has* layers of jelly, custard and cream. It also *has a* topping. // 蛋糕 *有* 果凍層,奶酪層和奶油層,頂部還 *有* 裝飾配料。 function createTrifle() { return { type: 'trifle', layers: [ createJelly(), createCustard(), createCream() ], topping: createAlmonds() }; }
3.異步的工廠函數(shù)
并非所有工廠都會(huì)立即返回?cái)?shù)據(jù)。例如,有些必須先獲取數(shù)據(jù)。在這些情況下,我們可以返回 Promises 來(lái)定義工廠函數(shù)。
function getMeal(menuUrl) { return new Promise((resolve, reject) => { fetch(menuUrl) .then(result => { resolve({ type: 'meal', courses: result.json() }); }) .catch(reject); }); }
這種深度嵌套的縮進(jìn)會(huì)使異步工廠難以閱讀和測(cè)試。將它們分解成多個(gè)不同的工廠通常是有幫助的,可以使用如下編寫。
function getMeal(menuUrl) { return fetch(menuUrl) .then(result => result.json()) .then(json => createMeal(json)); } function createMeal(courses=[]) { return { type: 'meal', courses }; }
當(dāng)然,我們可以使用回調(diào)函數(shù),但是我們已經(jīng)有了 Promise.all 這樣的工具返回 Promises 來(lái)定義工廠函數(shù)。
function getWeeksMeals() { const menuUrl = 'jsfood.com/'; return Promise.all([ getMeal(`${menuUrl}/monday`), getMeal(`${menuUrl}/tuesday`), getMeal(`${menuUrl}/wednesday`), getMeal(`${menuUrl}/thursday`), getMeal(`${menuUrl}/friday`) ]); }
我們使用 get 而不是 create 作為命名約定來(lái)顯示這些工廠做一些異步工作和返回promise。
4.函數(shù)和方法
到目前為止,我們還沒有看到任何工廠用方法返回對(duì)象,這是故意的。這是因?yàn)橐话銇?lái)說(shuō),我們不需要這么做。工廠允許我們從計(jì)算中分離我們的數(shù)據(jù)。這意味著我們總是能夠?qū)?duì)象序列化為JSON,這對(duì)于在會(huì)話之間持久化,通過(guò)HTTP或WebSockets發(fā)送它們,并將它們放入數(shù)據(jù)存儲(chǔ)很重要。
例如,不是在 jelly(果凍) 對(duì)象上定義 eat 方法,我們可以定義一個(gè)新的函數(shù),它接受一個(gè)對(duì)象作為參數(shù)并返回一個(gè)修改的版本。
function eatJelly(jelly) { if(jelly.scoops > 0) { jelly.scoops -= 1; } return jelly; }
一點(diǎn)點(diǎn)句法幫助使這是一個(gè)可行的模式,那些喜歡編程而不改變數(shù)據(jù)結(jié)構(gòu)的人。對(duì)于那些喜歡編程而不改變數(shù)據(jù)結(jié)構(gòu)的人來(lái)說(shuō),使用 ES6 的 ... 語(yǔ)法 是一個(gè)可行的模式。
function eat(jelly) { if(jelly.scoops > 0) { return { ...jelly, scoops: jelly.scoops - 1 }; } else { return jelly; } }
現(xiàn)在,不是這樣寫:
import { createJelly } from './jelly'; createJelly().eat();
而是這樣寫
import { createJelly, eatJelly } from './jelly'; eatJelly(createJelly());
最終結(jié)果是一個(gè)函數(shù),它接受一個(gè)對(duì)象并返回一個(gè)對(duì)象。我們稱之為返回對(duì)象的函數(shù)是什么? 一個(gè)工廠!
5.高級(jí)工廠
將工廠傳遞給 高階函數(shù) ,這將給我們帶來(lái)巨大的控制力。例如,我們可以使用這個(gè)概念來(lái)創(chuàng)建一個(gè)增強(qiáng)的對(duì)象。
function giveTimestamp(factory) { return (...args) => { const instance = factory(...args); const time = Date.now(); return { time, instance }; }; } const createOrder = giveTimestamp(function(ingredients) { return { type: 'order', ingredients }; });
這個(gè)增強(qiáng)的對(duì)象采用一個(gè)現(xiàn)有工廠,并將其包裝以創(chuàng)建返回帶有時(shí)間戳實(shí)例的工廠?;蛘撸绻覀兿胍_保一個(gè)工廠返回不可變的對(duì)象,我們可以用 freezer 來(lái)增強(qiáng)它。
function freezer(factory) { return (...args) => Object.freeze(factory(...args))); } const createImmutableIceCream = freezer(createIceCream); createImmutableIceCream('strawberry').flavour = 'mint'; // Error!
6.結(jié)論
作為一個(gè) 聰明的程序員 曾經(jīng)說(shuō)過(guò):從沒有抽象比錯(cuò)誤的抽象更容易回收。JavaScript項(xiàng)目有一個(gè)趨勢(shì),變得難以測(cè)試和重構(gòu),因?yàn)槲覀兘?jīng)常鼓勵(lì)使用復(fù)雜的抽象層。原型和類實(shí)現(xiàn)一個(gè)簡(jiǎn)單的想法使用復(fù)雜和不人性的工具,如 new 和 this ,即使現(xiàn)在,這仍然引起 各種各樣的困惑 -幾年后他們被添加到語(yǔ)言。對(duì)象和函數(shù)對(duì)于來(lái)自大多數(shù)語(yǔ)言背景的程序員來(lái)說(shuō)是有意義的,并且都是JavaScript中的原始類型,所以可以說(shuō)工廠不是抽象的!對(duì)象和函數(shù)對(duì)來(lái)自大多數(shù)背景的程序員都有意義,并且都是JavaScript中的原始類型,所以可以說(shuō)工廠不是抽象的!使用這些簡(jiǎn)單的構(gòu)建塊使得我們的代碼對(duì)于沒有經(jīng)驗(yàn)的程序員更加友好,這絕對(duì)是我們應(yīng)該關(guān)心的事情。工廠鼓勵(lì)我們用原始數(shù)據(jù)來(lái)模擬復(fù)雜和異步數(shù)據(jù),原始數(shù)據(jù)具有組合的自然能力,而不強(qiáng)迫我們?nèi)プ鲆恍└呒?jí)抽象。 當(dāng)我們堅(jiān)持簡(jiǎn)單時(shí),JavaScript更甜蜜!
以上所述是小編給大家介紹的JavaScript中的工廠函數(shù),希望對(duì)大家有所幫助,如果大家有任何疑問請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)億速云網(wǎng)站的支持!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。