溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

web開發(fā)中函數(shù)柯里化的示例分析

發(fā)布時(shí)間:2021-08-23 14:26:17 來源:億速云 閱讀:141 作者:小新 欄目:web開發(fā)

這篇文章給大家分享的是有關(guān)web開發(fā)中函數(shù)柯里化的示例分析的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

前言

函數(shù)柯里化就是將多參簡(jiǎn)化為單參數(shù)的一種技術(shù)方式,其最終支持的是方法的連續(xù)調(diào)用,每次返回新的函數(shù),在最終符合條件或者使用完所有的傳參時(shí)終止函數(shù)調(diào)用。

場(chǎng)景實(shí)例

與其他文章不同,我在本文會(huì)重點(diǎn)分享一些柯里化的經(jīng)典使用場(chǎng)景,讓你在學(xué)會(huì)這點(diǎn)技巧后能切實(shí)的提升代碼的可維護(hù)性。

編寫可重用小模塊代碼

比如我們有個(gè)方法部分邏輯前置是相同的,后面的執(zhí)行是因?yàn)閰?shù)不同導(dǎo)致結(jié)果不同的,下面是代碼部分。
計(jì)算商品的折扣,我們需要根據(jù)不同的折扣以及商品的入?yún)⒎祷仄鋵?shí)際的價(jià)格。

// before
function getPrice(price,discount){
	return price * discount;
}

let price = getPrice(500,0.1);


// after 
function getPrice(discount){
	return price =>{
 	return price * discount
 }
}
// 使用,在這種使用效果下,我們可以固定的肢解拿到百分之十折扣的函數(shù),
//也就是針對(duì)使用0.1折扣的商品價(jià)格都可以簡(jiǎn)化這個(gè)折扣的傳遞,從而達(dá)到簡(jiǎn)化參數(shù)的目的
//那么從函數(shù)的運(yùn)行上來講,也比之前的效率高了,如果解析折扣的過程比較復(fù)雜
let tenDiscount = getPrice(0.1);
let price = tenDiscount(500);

let price = getPrice(0.1)(500)

看上去有點(diǎn)雞肋,因?yàn)槲覀儽緛淼膶懛ê芎?jiǎn)單,使用了柯里化反而讓簡(jiǎn)單的事情變得復(fù)雜了,這主要是因?yàn)闆]有達(dá)到我們要把一個(gè)函數(shù)變成柯里化的經(jīng)典場(chǎng)景。假如你下面的代碼變成了下面這樣,也許你就能覺察出如果有使用柯里化就會(huì)非常方便了,因?yàn)獒槍?duì)第一個(gè)參數(shù)做了若干的處理,甚至可以稱為一個(gè)算法或者完整的邏輯判斷流程,那么如果有多個(gè)參數(shù)調(diào)用都涉及這個(gè)方法的調(diào)用,同一個(gè)參數(shù)的這部分邏輯是相同可以共用跳過的。codepen連接:鏈接

// complexed fun 
function getPriceComplex(price,discount){
 let actualDiscount = 1;
 if(discount > 0.8 ) {
 	actualDiscount = 0.8;
 } else if(discount > 0.5){
 	actualDiscount = 0.5;
 } else {
 actualDiscount = 0.1;
 }
 let actualPrice = price - price % 100 ;
	return actualPrice * actualDiscount;
}

// complexed fun better
function getPriceComplexBetter(discount){
 let actualDiscount = 1;
 if(discount > 0.8 ) {
 	actualDiscount = 0.8;
 } else if(discount > 0.5){
 	actualDiscount = 0.5;
 } else {
 actualDiscount = 0.1;
 }
 return price => {
 	 let actualPrice = price - price % 100 ;
			return actualPrice * actualDiscount;
 }
}


console.log(getPriceComplex(500,0.9))
let exp1 = getPriceComplexCp(0.9);
console.log(exp1);
/** price => {
 let actualPrice = price - price % 100;
 return actualPrice * actualDiscount;
}*/
// 相同的輸入?yún)?shù)時(shí) 可以緩存下之前代碼邏輯的執(zhí)行結(jié)果 實(shí)現(xiàn)模塊的可重用,如果你之前的邏輯是一個(gè)純函數(shù)
console.log(exp1(500))// 400
console.log(exp1(400))// 320


// get real discount 
// 當(dāng)你針對(duì)第一個(gè)參數(shù)的邏輯較為復(fù)雜時(shí),出于可維護(hù)角度,建議如此 ;
// 當(dāng)你另外一個(gè)邏輯也是基于這個(gè)返回結(jié)果時(shí),出于重用角度,建議如此
function getActualDiscount(discount){
 let actualDiscount = 1;
 if(discount > 0.8 ) {
 	actualDiscount = 0.8;
 } else if(discount > 0.5){
 	actualDiscount = 0.5;
 } else {
 actualDiscount = 0.1;
 }
 return actualDiscount;
}
// complexed fun best
function getPriceComplexBest(discount){
 let actualDiscount =getActualDiscount(discount);
 return price => {
 	 let actualPrice = price - price % 100 ;
			return actualPrice * actualDiscount;
 }
}

總結(jié),無論如何,我們使用某種技巧或者封裝或者其他,都是為了讓代碼更可用,原先復(fù)雜不可測(cè)試、不可理解的代碼變得更有調(diào)理,更節(jié)省性能的角度出發(fā)的,當(dāng)你的思維方式中有這種的時(shí)候,你就不會(huì)覺得是為了形式而使用,而是你的編碼習(xí)慣或者風(fēng)格就是如此。

簡(jiǎn)單改造普通函數(shù)為柯里

假如我們需要把一個(gè)原來非柯里的函數(shù)如何快速改造,在不影響原來主要代碼邏輯的情況下,想下我們代碼可能如何寫?

// 只考慮兩個(gè)參數(shù)
function add(a,b){
 return a + b
}

// 但如果你是用柯里化的方式:兩個(gè)參數(shù)的時(shí)候 ,但這樣對(duì)原代碼變動(dòng)非常大,對(duì)于一些復(fù)雜的邏輯,這基本不可能
function curryAdd(...args){
 return (...newArgs) => {
 	return anoNumber * number;
 };
}

// 我們寫一個(gè)通用的柯里化函數(shù)的方式,經(jīng)過這個(gè)函數(shù)的轉(zhuǎn)換,我們可以將調(diào)用方式簡(jiǎn)化
function curry = (fn,...args){
	return (..._args)=>{
 	return fn(...args, ..._arg);
 }
}

let curryAdd = curry(add,10);
let curryAdd2 = curryAdd(11)

不定參數(shù)的累加

一個(gè)比較經(jīng)典的練手題,把下面的代碼用柯里化的方式實(shí)現(xiàn),其難點(diǎn)簡(jiǎn)單分析如下:如果你沒有了解過柯里化,可能覺得基本無法完成。

1 動(dòng)態(tài)入?yún)€(gè)數(shù),這個(gè)也許還可以通過arguments循環(huán)完成2 每次都能接受新的參數(shù)繼續(xù)累加,這必須是返回新函數(shù)并帶有之前的結(jié)果,要求是具有柯里化特點(diǎn)3 每次不在追加參數(shù)時(shí),需要能得到的值,這個(gè)需要你了解toString方法來改變結(jié)果值

實(shí)現(xiàn)一個(gè)add方法,使計(jì)算結(jié)果能夠滿足如下預(yù)期: add(1)(2)(3) = 6

add(1, 2, 3)(4) = 10

add(1)(2)(3)(4)(5) = 15

function add() {
 // 第一次執(zhí)行時(shí),定義一個(gè)數(shù)組專門用來存儲(chǔ)所有的參數(shù)
 var _args = [].slice.call(arguments);
 // 在內(nèi)部聲明一個(gè)函數(shù),利用閉包的特性保存_args并收集所有的參數(shù)值,執(zhí)行時(shí)已經(jīng)收集所有參數(shù)為數(shù)組
 var adder = function () {
  var _adder = function() {
   // 執(zhí)行收集動(dòng)作,每次傳入的參數(shù)都累加到原參數(shù)
   [].push.apply(_args, [].slice.call(arguments));
   return _adder;
  };
  // 利用隱式轉(zhuǎn)換的特性,當(dāng)最后執(zhí)行時(shí)隱式轉(zhuǎn)換,并計(jì)算最終的值返回
  _adder.toString = function () {
   return _args.reduce(function (a, b) {
    return a + b;
   });
  }
  return _adder;
 }
 return adder(_args);
}

備注:codepen中的console.log方法被重寫,會(huì)有報(bào)錯(cuò)的問題,你可以直接通過瀏覽器的console控制臺(tái)調(diào)試這個(gè)方法。

部分參數(shù)應(yīng)用

部分參數(shù)應(yīng)用是指有些場(chǎng)景是希望固定傳遞多個(gè)參數(shù),來得到其固定的函數(shù),然后基于這個(gè)函數(shù)去執(zhí)行代碼。類似于第一個(gè)例子中的一個(gè)折扣參數(shù)得出折扣算法的使用。我們將第一個(gè)例子再復(fù)雜化一些。就會(huì)變成這樣的。

function getActualDiscount(custoemrLevel,discount){
	
}
function getPriceComplex (custoemrLevel,discount){
	let actualDiscount = getActualDiscount(custoemrLevel,discount);
 return price=>{
 	return price * actualDiscount;
 }
}
// 等級(jí)一的折扣策略 
let strategyLev1WithOnepoint = getPriceComplex('lev1',0.1) ;
let actualPrice = strategyLev1WithOnepoint(500);

感謝各位的閱讀!關(guān)于“web開發(fā)中函數(shù)柯里化的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(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)容。

AI