App下載

解析:JavaScript中的函數(shù)式編程

猿友 2020-07-27 17:24:23 瀏覽數(shù) (2473)
反饋

JavaScript是一種很受歡迎的編程語(yǔ)言,今天整理這篇文章是為了讓大家更深入了解一下JavaScript。下面我將展示一些有關(guān)如何在JavaScript中應(yīng)用函數(shù)式編程的例子。

JavaScript中的函數(shù)式編程

即使函數(shù)式編程可以極大地改善應(yīng)用程序的代碼,但其原理在開始時(shí)可能會(huì)有些挑戰(zhàn)。由于詳細(xì)解釋所有這些都將花費(fèi)大量時(shí)間,因此我們決定使用兩個(gè)實(shí)際的代碼示例來(lái)介紹這些概念。

1.Maybe Monad

在第一個(gè)示例中,我們找到一種避免驗(yàn)證變量是否為Null的方法。假設(shè)在我們的應(yīng)用程序中,我們可以找到具有以下格式的用戶:

const someUser = {
 name: 'some_name',
 email: 'some@email.com',
 settings: {
  language: 'sp'
 }
};

有一個(gè)功能,可以以用戶設(shè)置的語(yǔ)言返回歡迎消息。

const allGreetings = {
 'en': '嗨',
 'sp': '你好',
 'fr': '歡迎你'
};
const getGreetingForUser = (user) => {
 //將要執(zhí)行
}

來(lái)看一個(gè)遵循命令式模型的“getGreetingForUser”函數(shù)的實(shí)現(xiàn):

const getGreetingForUser = (user) => {
 if (!user) {
   return allGreetings.en;
 }
 if (user.settings && user.settings.language) {
   if (allGreetings[user.settings.language]) {
     return allGreetings[user.settings.language]
   } else {
     return allGreetings.en;
   }
 } else {
   return allGreetings.en;
 }
};
console.log(getGreetingForUser(someUser));

如上面所看到的,必須檢查用戶是否已經(jīng)存在,是否已設(shè)置語(yǔ)言,以及是否已準(zhǔn)備好歡迎消息。如果出現(xiàn)問(wèn)題,我們將以默認(rèn)語(yǔ)言返回一條消息。

現(xiàn)在,讓我們看一下相同的函數(shù),但是這次我們將在其實(shí)現(xiàn)中使用函數(shù)式編程:

const getGreetingForUser = (user) => {
  return RamdaFantasy.Maybe(user)
    .map(Ramda.path(['settings', 'language']))
    .chain(maybeGreeting);
};
const maybeGreeting = Ramda.curry((greetingsList, userLanguage) => {
  return RamdaFantasy.Maybe(greetingsList[userLanguage]);
})(allGreetings);
console.log(getGreetingForUser(someUser).getOrElse(allGreetings.en));

為了處理可能為null或未定義的情況,我們將使用Maybe Monad。這使我們可以在對(duì)象周圍創(chuàng)建包裝器,并為空對(duì)象分配默認(rèn)行為。

讓我們比較兩種解決方案:

//代替驗(yàn)證用戶是否為空
if (!user) {
  return allGreetings.en;
}
//我們將用:
RamdaFantasy.Maybe(user) //我們將用戶添加到包裝器中

//代替:
 if (user.settings && user.settings.language) {
   if (allGreetings[user.settings.language]) {
//我們將用:
 <userMaybe>.map(Ramda.path(['settings', 'language'])) //如果存在數(shù)據(jù),映射將會(huì)用它

//不是在else中返回默認(rèn)值:
 return indexURLs['en'];
.getOrElse(allGreetings。EN)
// 指定的默認(rèn)值。

2 Either Monad

當(dāng)我們知道存在空錯(cuò)誤時(shí)的默認(rèn)行為時(shí),Maybe Monad非常有用。

但是,如果我們有一個(gè)引發(fā)錯(cuò)誤的函數(shù),或者我們將各種引發(fā)錯(cuò)誤的函數(shù)鏈接在一起,并且我們想知道哪個(gè)發(fā)生了故障,則可以改用Either Monad。

現(xiàn)在,讓我們假設(shè)我們要計(jì)算產(chǎn)品的價(jià)格,同時(shí)考慮增值稅和可能的折扣。我們已經(jīng)有了以下代碼:

const withTaxes = (tax, price) => {
 if (!_.isNumber(price)) {
 return new Error("Price is not numeric");
 }
 return price + (tax * price);
};
const withDiscount = (dis, price) => { 
  if (!_.isNumber(price)) { 
    return new Error("Price is not numeric"); 
  } 
  if (price < 5) 
    return new Error("Discounts not available for low-priced items"); 
  } 
  return price - (price * dis);5
}; 
const isError = (e) => e && e.name === 'Error';
const calculatePrice(price, tax, discount) => { 
//將要執(zhí)行
}

讓我們來(lái)看一個(gè)遵循命令式模型的“calculatePrice”函數(shù)的實(shí)現(xiàn):

const calculatePrice = (price, tax, discount) => {
  const priceWithTaxes = withTaxes(tax, price);
  if (isError(priceWithTaxes)) {
    return console.log('Error: ' + priceWithTaxes.message);
  }
  const priceWithTaxesAndDiscount = withDiscount(discount, priceWithTaxes);
  if (isError(priceWithTaxesAndDiscount)) {
    return console.log('Error: ' + priceWithTaxesAndDiscount.message);
  }
  console.log('Total Price: ' + priceWithTaxesAndDiscount);
}
//我們計(jì)算出價(jià)值25的產(chǎn)品(含21%的增值稅和10%的折扣)的最終價(jià)格。
 calculatePrice(25, 0.21, 0.10)

現(xiàn)在,讓我們了解如何使用Either Monad重寫此函數(shù)。

都有兩個(gè)構(gòu)造函數(shù),LeftRight。我們要實(shí)現(xiàn)的是將異常存儲(chǔ)到Left構(gòu)造函數(shù),并將正常結(jié)果(快樂(lè)路徑)存儲(chǔ)到Right構(gòu)造函數(shù)。

首先,將更改已經(jīng)存在的withTaxeswithDiscount函數(shù),以便在出現(xiàn)錯(cuò)誤時(shí)它們返回Left,在一切正常的情況下返回Right

const withTaxes = Ramda.curry((tax, price) => {
  if (!_.isNumber(price)) {
    return RamdaFantasy.Either.Left(new Error("Price is not numeric"));
  }
  return RamdaFantasy.Either.Right(price + (tax * price)); 
});
const withDiscount = Ramda.curry((dis, price) => {
  if (!_.isNumber(price)) {
    return RamdaFantasy.Either.Left(new Error("Price is not numeric")); 
  }
  if (price < 5) { 
    return RamdaFantasy.Either.Left(new Error("Discounts not available for low-priced items")); 
  } 
  return RamdaFantasy.Either.Right(price - (price * dis)); 
});

然后,我們?yōu)?code>Right案例創(chuàng)建一個(gè)函數(shù)(顯示價(jià)格),為Left案例創(chuàng)建另一個(gè)函數(shù)(顯示錯(cuò)誤),然后使用它們創(chuàng)建Either Monad

const showPrice = (total) => { console.log('Price: ' + total) }; 
const showError = (error) => { console.log('Error: ' + error.message); }; 
const eitherErrorOrPrice = RamdaFantasy.Either.either(showError, showPrice);

最后,只需要執(zhí)行Monad來(lái)計(jì)算最終價(jià)格:

//計(jì)算出價(jià)值25的產(chǎn)品(含21%的增值稅和10%的折扣)的最終價(jià)格。
 eitherErrorOrPrice(
   RamdaFantasy.Either.Right(25)
     .chain(withTaxes(0.21))
     .chain(withDiscount(0.1))
)

結(jié)論:JavaScript中的函數(shù)式編程

正如我們所看到的,一旦用MaybeEither單子分解了代碼,就沒(méi)有那么復(fù)雜了。如果使用得當(dāng),它們可以使我們的代碼更易于閱讀和維護(hù)。

唯一的不便是我們需要克服的初始障礙,但這可以通過(guò)在網(wǎng)上一些示例并進(jìn)行一些測(cè)試來(lái)完成。

以上就是JavaScript中應(yīng)用函數(shù)式編程的示例,希望能對(duì)大家有所幫助。然后想學(xué)習(xí)JavaScript的同學(xué)可以點(diǎn)以下鏈接

JavaScript教程:http://www.o2fo.com/javascript/

JavaScript微課:http://www.o2fo.com/minicourse/play/jscourse

文章參考來(lái)源:www.toutiao.com/a6836176173207126541/

0 人點(diǎn)贊