詳解用場景去理解函數(shù)柯里化(入門篇)
前言
函數(shù)柯里化就是將多參簡化為單參數(shù)的一種技術(shù)方式,其最終支持的是方法的連續(xù)調(diào)用,每次返回新的函數(shù),在最終符合條件或者使用完所有的傳參時終止函數(shù)調(diào)用。
場景實例
與其他文章不同,我在本文會重點分享一些柯里化的經(jīng)典使用場景,讓你在學(xué)會這點技巧后能切實的提升代碼的可維護性。
編寫可重用小模塊代碼
比如我們有個方法部分邏輯前置是相同的,后面的執(zhí)行是因為參數(shù)不同導(dǎo)致結(jié)果不同的,下面是代碼部分。
計算商品的折扣,我們需要根據(jù)不同的折扣以及商品的入?yún)⒎祷仄鋵嶋H的價格。
// before function getPrice(price,discount){ return price * discount; } let price = getPrice(500,0.1); // after function getPrice(discount){ return price =>{ return price * discount } } // 使用,在這種使用效果下,我們可以固定的肢解拿到百分之十折扣的函數(shù), //也就是針對使用0.1折扣的商品價格都可以簡化這個折扣的傳遞,從而達到簡化參數(shù)的目的 //那么從函數(shù)的運行上來講,也比之前的效率高了,如果解析折扣的過程比較復(fù)雜 let tenDiscount = getPrice(0.1); let price = tenDiscount(500); let price = getPrice(0.1)(500)
看上去有點雞肋,因為我們本來的寫法很簡單,使用了柯里化反而讓簡單的事情變得復(fù)雜了,這主要是因為沒有達到我們要把一個函數(shù)變成柯里化的經(jīng)典場景。假如你下面的代碼變成了下面這樣,也許你就能覺察出如果有使用柯里化就會非常方便了,因為針對第一個參數(shù)做了若干的處理,甚至可以稱為一個算法或者完整的邏輯判斷流程,那么如果有多個參數(shù)調(diào)用都涉及這個方法的調(diào)用,同一個參數(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ù)時 可以緩存下之前代碼邏輯的執(zhí)行結(jié)果 實現(xiàn)模塊的可重用,如果你之前的邏輯是一個純函數(shù) console.log(exp1(500))// 400 console.log(exp1(400))// 320 // get real discount // 當(dāng)你針對第一個參數(shù)的邏輯較為復(fù)雜時,出于可維護角度,建議如此 ; // 當(dāng)你另外一個邏輯也是基于這個返回結(jié)果時,出于重用角度,建議如此 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ù)雜不可測試、不可理解的代碼變得更有調(diào)理,更節(jié)省性能的角度出發(fā)的,當(dāng)你的思維方式中有這種的時候,你就不會覺得是為了形式而使用,而是你的編碼習(xí)慣或者風(fēng)格就是如此。
簡單改造普通函數(shù)為柯里
假如我們需要把一個原來非柯里的函數(shù)如何快速改造,在不影響原來主要代碼邏輯的情況下,想下我們代碼可能如何寫?
// 只考慮兩個參數(shù) function add(a,b){ return a + b } // 但如果你是用柯里化的方式:兩個參數(shù)的時候 ,但這樣對原代碼變動非常大,對于一些復(fù)雜的邏輯,這基本不可能 function curryAdd(...args){ return (...newArgs) => { return anoNumber * number; }; } // 我們寫一個通用的柯里化函數(shù)的方式,經(jīng)過這個函數(shù)的轉(zhuǎn)換,我們可以將調(diào)用方式簡化 function curry = (fn,...args){ return (..._args)=>{ return fn(...args, ..._arg); } } let curryAdd = curry(add,10); let curryAdd2 = curryAdd(11)
不定參數(shù)的累加
一個比較經(jīng)典的練手題,把下面的代碼用柯里化的方式實現(xiàn),其難點簡單分析如下:如果你沒有了解過柯里化,可能覺得基本無法完成。
1 動態(tài)入?yún)€數(shù),這個也許還可以通過arguments循環(huán)完成2 每次都能接受新的參數(shù)繼續(xù)累加,這必須是返回新函數(shù)并帶有之前的結(jié)果,要求是具有柯里化特點3 每次不在追加參數(shù)時,需要能得到的值,這個需要你了解toString方法來改變結(jié)果值
實現(xiàn)一個add方法,使計算結(jié)果能夠滿足如下預(yù)期: add(1)(2)(3) = 6
add(1, 2, 3)(4) = 10
add(1)(2)(3)(4)(5) = 15
function add() { // 第一次執(zhí)行時,定義一個數(shù)組專門用來存儲所有的參數(shù) var _args = [].slice.call(arguments); // 在內(nèi)部聲明一個函數(shù),利用閉包的特性保存_args并收集所有的參數(shù)值,執(zhí)行時已經(jīng)收集所有參數(shù)為數(shù)組 var adder = function () { var _adder = function() { // 執(zhí)行收集動作,每次傳入的參數(shù)都累加到原參數(shù) [].push.apply(_args, [].slice.call(arguments)); return _adder; }; // 利用隱式轉(zhuǎn)換的特性,當(dāng)最后執(zhí)行時隱式轉(zhuǎn)換,并計算最終的值返回 _adder.toString = function () { return _args.reduce(function (a, b) { return a + b; }); } return _adder; } return adder(_args); }
備注:codepen中的console.log方法被重寫,會有報錯的問題,你可以直接通過瀏覽器的console控制臺調(diào)試這個方法。
部分參數(shù)應(yīng)用
部分參數(shù)應(yīng)用是指有些場景是希望固定傳遞多個參數(shù),來得到其固定的函數(shù),然后基于這個函數(shù)去執(zhí)行代碼。類似于第一個例子中的一個折扣參數(shù)得出折扣算法的使用。我們將第一個例子再復(fù)雜化一些。就會變成這樣的。
function getActualDiscount(custoemrLevel,discount){ } function getPriceComplex (custoemrLevel,discount){ let actualDiscount = getActualDiscount(custoemrLevel,discount); return price=>{ return price * actualDiscount; } } // 等級一的折扣策略 let strategyLev1WithOnepoint = getPriceComplex('lev1',0.1) ; let actualPrice = strategyLev1WithOnepoint(500);
以上所述是小編給大家介紹的用場景去理解函數(shù)柯里化(入門篇)詳解整合,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
相關(guān)文章
Js查找字符串中出現(xiàn)次數(shù)最多的字符及個數(shù)實例解析
這篇文章主要介紹了Js查找字符串中出現(xiàn)次數(shù)最多的字符及個數(shù) ,本文分為傳統(tǒng)寫法和正則寫法兩種方法給大家介紹了js查找字符串出現(xiàn)次數(shù)最多的字符及個數(shù),非常不錯,感興趣的朋友參考下吧2016-09-09修改layui的后臺模板的左側(cè)導(dǎo)航欄可以伸縮的方法
今天小編就為大家分享一篇修改layui的后臺模板的左側(cè)導(dǎo)航欄可以伸縮的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-09-09KnockoutJS 3.X API 第四章之表單submit、enable、disable綁定
Knockout是一個以數(shù)據(jù)模型(data model)為基礎(chǔ)的能夠幫助你創(chuàng)建富文本,響應(yīng)顯示和編輯用戶界面的JavaScript類庫。這篇文章介紹了KnockoutJS 3.X API 第四章之表單submit、enable、disable綁定的相關(guān)知識,感興趣的朋友一起看看吧2016-10-10JavaScript中的console.dir()函數(shù)介紹
這篇文章主要介紹了JavaScript中的console.dir()函數(shù)介紹,console.dir主要用來dump某些對象的詳細(xì)信息,需要的朋友可以參考下2014-12-12JS判斷移動端訪問設(shè)備并加載對應(yīng)CSS樣式
JS判斷不同web訪問環(huán)境,主要針對移動設(shè)備,提供相對應(yīng)的解析方案,本例是加載不同的css樣式2014-06-06