本文小编为大家详细介绍“JavaScript中的函数式编程怎么应用”,内容详细,步骤清晰,细节处理妥当,希望这篇“JavaScript中的函数式编程怎么应用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。
JavaScript中的函数式编程
即使函数式编程可以极大地改善应用程序的代码,但其原理在开始时可能会有些挑战。由于详细解释所有这些都将花费大量时间,因此我们决定使用两个实际的代码示例来介绍这些概念。
1.Maybe Monad
在第一个示例中,我们找到一种避免验证变量是否为Null
的方法。假设在我们的应用程序中,我们可以找到具有以下格式的用户:
const someUser = { name: 'some_name', email: 'some@email.com', settings: { language: 'sp' }};
有一个功能,可以以用户设置的语言返回欢迎消息。
const allGreetings = { 'en': '嗨', 'sp': '你好', 'fr': '欢迎你'};const getGreetingForUser = (user) => { //将要执行}
来看一个遵循命令式模型的“getGreetingForUser
”函数的实现:
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));
如上面所看到的,必须检查用户是否已经存在,是否已设置语言,以及是否已准备好欢迎消息。如果出现问题,我们将以默认语言返回一条消息。
现在,让我们看一下相同的函数,但是这次我们将在其实现中使用函数式编程:
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
。这使我们可以在对象周围创建包装器,并为空对象分配默认行为。
让我们比较两种解决方案:
//代替验证用户是否为空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'])) //如果存在数据,映射将会用它
//不是在else中返回默认值: return indexURLs['en'];.getOrElse(allGreetings。EN)// 指定的默认值。
2 Either Monad
当我们知道存在空错误时的默认行为时,Maybe Monad
非常有用。
但是,如果我们有一个引发错误的函数,或者我们将各种引发错误的函数链接在一起,并且我们想知道哪个发生了故障,则可以改用Either Monad
。
现在,让我们假设我们要计算产品的价格,同时考虑增值税和可能的折扣。我们已经有了以下代码:
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) => { //将要执行}
让我们来看一个遵循命令式模型的“calculatePrice
”函数的实现:
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);}//我们计算出价值25的产品(含21%的增值税和10%的折扣)的最终价格。 calculatePrice(25, 0.21, 0.10)
现在,让我们了解如何使用Either Monad
重写此函数。
都有两个构造函数,Left
和Right
。我们要实现的是将异常存储到Left
构造函数,并将正常结果(快乐路径)存储到Right
构造函数。
首先,将更改已经存在的withTaxes
和withDiscount
函数,以便在出现错误时它们返回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)); });
然后,我们为Right
案例创建一个函数(显示价格),为Left
案例创建另一个函数(显示错误),然后使用它们创建Either Monad
:
const showPrice = (total) => { console.log('Price: ' + total) }; const showError = (error) => { console.log('Error: ' + error.message); }; const eitherErrorOrPrice = RamdaFantasy.Either.either(showError, showPrice);
最后,只需要执行Monad来计算最终价格:
//计算出价值25的产品(含21%的增值税和10%的折扣)的最终价格。 eitherErrorOrPrice( RamdaFantasy.Either.Right(25) .chain(withTaxes(0.21)) .chain(withDiscount(0.1)))
读到这里,这篇“JavaScript中的函数式编程怎么应用”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。