欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JS函數(shù)式編程之純函數(shù)、柯里化以及組合函數(shù)

 更新時間:2023年01月08日 11:55:30   作者:虛幻私塾  
這篇文章主要介紹了JS函數(shù)式編程之純函數(shù)、柯里化以及組合函數(shù),文章對三個函數(shù)進行分析講解,內(nèi)容也很容易理解,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下

前言

函數(shù)式編程(Functional Programming),又稱為泛函編程,是一種編程范式。

早在很久以前就提出了函數(shù)式編程這個概念了,而后面一直長期被面向?qū)ο缶幊趟y(tǒng)治著,最近幾年函數(shù)式編程又回到了大家的視野中,JavaScript是一門以函數(shù)為第一公民的語言,必定是支持這一種編程范式的。

下面就來談?wù)凧avaScript函數(shù)式編程中的核心概念純函數(shù)、柯里化以及組合函數(shù)。

純函數(shù)

純函數(shù)的概念

對于純函數(shù)的定義,維基百科中是這樣描述的:在程序設(shè)計中,若函數(shù)符合以下條件,那么這個函數(shù)被稱之為純函數(shù)。

  • 此函數(shù)在相同的輸入值時,需產(chǎn)生相同的輸出;
  • 函數(shù)的輸入和輸出值以外的其他隱藏信息或狀態(tài)無關(guān),也和由I/O設(shè)備產(chǎn)生的外部輸出無關(guān);
  • 該函數(shù)不能有語義上可觀察的函數(shù)副作用,諸如“觸發(fā)事件”,使輸出設(shè)備輸出,或更改輸出值以外物件的內(nèi)容等;

對以上描述總結(jié)就是:

  • 對于相同的輸入,永遠會得到相同的輸出;
  • 在函數(shù)的執(zhí)行過程中,沒有任何可觀察的副作用;
  • 同時也不依賴外部環(huán)境的狀態(tài);

副作用

上面提到了一個詞叫“副作用”,那么什么是副作用呢?

  • 通常我們所說的副作用大多數(shù)是指藥會產(chǎn)生的副作用;
  • 而在計算機科學(xué)中,副作用指在執(zhí)行一個函數(shù)時,除了得到函數(shù)的返回值以外,還在函數(shù)調(diào)用時產(chǎn)生了附加的影響,比如修改了全局變量的狀態(tài),修改了傳入的參數(shù)或得到了其它的輸出內(nèi)容等;

純函數(shù)案例

  • 編寫一個求和的函數(shù)sum,只要我們輸入了固定的值,sum函數(shù)就會給我們返回固定的結(jié)果,且不會產(chǎn)生任何副作用。
function sum(a, b) {
 return a + b
}

const res = sum(10, 20)
console.log(res) // 30
  • 以下的sum函數(shù)雖然對于固定的輸入也會返回固定的輸出,但是函數(shù)內(nèi)部修改了全局變量message,就認(rèn)定為產(chǎn)生了副作用,不屬于純函數(shù)。
let message = 'hello'
function sum(a, b) {
 message = 'hi'
 return a + b
}
  • 在JavaScript中也提供了許多的內(nèi)置方法,有些是純函數(shù),有些則不是。像操作數(shù)組的兩個方法slice和splice。

1.slice方法就是一個純函數(shù),因為對于同一個數(shù)組固定的輸入可以得到固定的輸出,且沒有任何副作用;

const nums = [1, 2, 3, 4, 5]
const newNums = nums.slice(1, 3)
console.log(newNums) // [2, 3]
console.log(nums) // [ 1, 2, 3, 4, 5 ]

2.splice方法不是一個純函數(shù),因為它改變了原數(shù)組nums;

const nums = [1, 2, 3, 4, 5]
const newNums = nums.splice(1, 3)
console.log(newNums) // [ 2, 3, 4 ]
console.log(nums) // [ 1, 5 ]

柯里化

柯里化的概念

對于柯里化的定義,維基百科中是這樣解釋的:

  • 柯里化是指把接收多個參數(shù)的函數(shù),變成接收一個單一參數(shù)(最初函數(shù)的第一個參數(shù))的函數(shù),并且返回接收余下的參數(shù),而且返回結(jié)果的新函數(shù)的技術(shù);
  • 柯里化聲稱**“如果你固定某些參數(shù),你將得到接受余下參數(shù)的一個函數(shù)”**;

總結(jié):只傳遞給函數(shù)一部分參數(shù)來調(diào)用它,讓它返回一個函數(shù)去處理剩余的參數(shù)的過程就稱之為柯里化。

函數(shù)柯里化的過程

編寫一個普通的三值求和函數(shù):

function sum(x, y, z) {
 return x + y + z
}
const res = sum(10, 20, 30)
console.log(res) // 60

將以上求和函數(shù)柯里化得:

  • 將傳入的三個參數(shù)進行拆解,依次返回一個函數(shù),并傳入一個參數(shù);
  • 在保證同樣功能的同時,其調(diào)用方式卻發(fā)生了變化;
  • 注意:在拆解參數(shù)時,不一定非要將參數(shù)拆成一個個的,也可以拆成2+1或1+2;
function sum(x) {
 return function(y) {
 return function(z) {
 return x + y + z
 }
 }
}
const res = sum(10)(20)(30)
console.log(res)

使用ES6箭頭函數(shù)簡寫為:

const sum = x => y => z => x + y + z

函數(shù)柯里化的特點及應(yīng)用

  • **讓函數(shù)的職責(zé)更加單一。**柯里化可以實現(xiàn)讓一個函數(shù)處理的問題盡可能的單一,而不是將一大堆邏輯交給一個函數(shù)來處理。

1.將上面的三值求和函數(shù)增加一個需求,在計算結(jié)果之前給每個值加上2,先看看不使用柯里化的實現(xiàn)效果:

function sum(x, y, z) {
 x = x + 2
 y = y + 2
 z = z + 2
 return x + y + z
}

2.柯里化的實現(xiàn)效果:

function sum(x) {
 x = x + 2
 return function(y) {
 y = y + 2
 return function(z) {
 z = z + 2
 return x + y + z
 }
 }
}

3.很明顯函數(shù)柯里化后,讓我們對每個參數(shù)的處理更加單一

  • **提高函數(shù)參數(shù)邏輯復(fù)用。**同樣使用上面的求和函數(shù),增加另一個需求,固定第一個參數(shù)的值為10,直接看柯里化的實現(xiàn)效果吧,后續(xù)函數(shù)調(diào)用時第一個參數(shù)值都為10的話,就可以直接調(diào)用sum10函數(shù)了。
function sum(x) {
 return function(y) {
 return function(z) {
 return x + y + z
 }
 }
}
const sum10 = sum(10) // 指定第一個參數(shù)值為10的函數(shù)
const res = sum10(20)(30)
console.log(res) // 60

自動柯里化函數(shù)的實現(xiàn)

function autoCurrying(fn) {
 // 1.拿到當(dāng)前需要柯里化函數(shù)的參數(shù)個數(shù)
 const fnLen = fn.length

 // 2.定義一個柯里化之后的函數(shù)
 function curried\_1(...args1) {
 // 2.1拿到當(dāng)前傳入?yún)?shù)的個數(shù)
 const argsLen = args1.length

 // 2.1.將當(dāng)前傳入?yún)?shù)個數(shù)和fn需要的參數(shù)個數(shù)進行比較
 if (argsLen >= fnLen) {
 // 如果當(dāng)前傳入的參數(shù)個數(shù)已經(jīng)大于等于fn需要的參數(shù)個數(shù)
 // 直接執(zhí)行fn,并在執(zhí)行時綁定this,并將對應(yīng)的參數(shù)數(shù)組傳入
 return fn.apply(this, args1)
 } else {
 // 如果傳入的參數(shù)不夠,說明需要繼續(xù)返回函數(shù)來接收參數(shù)
 function curried\_2(...args2) {
 // 將參數(shù)進行合并,遞歸調(diào)用curried\_1,直到參數(shù)達到fn需要的參數(shù)個數(shù)
 return curried\_1.apply(this, [...args1, ...args2])
 }

 // 返回繼續(xù)接收參數(shù)函數(shù)
 return curried\_2
 }
 }

 // 3.將柯里化的函數(shù)返回
 return curried\_1
}

測試:

function sum(x, y, z) {
 return x + y + z
}

const curryingSum = autoCurrying(sum)

const res1 = curryingSum(10)(20)(30)
const res2 = curryingSum(10, 20)(30)
const res3 = curryingSum(10)(20, 30)
const res4 = curryingSum(10, 20, 30)
console.log(res1) // 60
console.log(res2) // 60
console.log(res3) // 60
console.log(res4) // 60

組合函數(shù)

**組合函數(shù)(Compose Function)**是在JavaScript開發(fā)過程中一種對函數(shù)的使用技巧、模式。對某一個數(shù)據(jù)進行函數(shù)調(diào)用,執(zhí)行兩個函數(shù),這兩個函數(shù)需要依次執(zhí)行,所以需要將這兩個函數(shù)組合起來,自動依次調(diào)用,而這個過程就叫做函數(shù)的組合,組合形成的函數(shù)就叫做組合函數(shù)。

需求:對一個數(shù)字先進行乘法運算,再進行平方運算。

  • 一般情況下,需要先定義兩個函數(shù),然后再對其依次調(diào)用:
function double(num) {
 return num * 2
}
function square(num) {
 return num ** 2
}
const duobleResult = double(10)
const squareResult = square(duobleResult)
console.log(squareResult) // 400

實現(xiàn)一個組合函數(shù),將duoble和square兩個函數(shù)組合起來:

function composeFn(fn1, fn2) {
 return function(num) {
 return fn2(fn1(num))
 }
}
const execFn = composeFn(double, square)
const res = execFn(10)
console.log(res) // 400

實現(xiàn)一個自動組合函數(shù)的函數(shù):

function autoComposeFn(...fns) {
 // 1.拿到需要組合的函數(shù)個數(shù)
 const fnsLen = fns.length

 // 2.對傳入的函數(shù)進行邊界判斷,所有參數(shù)必須為函數(shù)
 for (let i = 0; i < fnsLen; i++) {
 if (typeof fns[i] !== 'function') {
 throw TypeError('The argument passed must be a function.')
 }
 }

 // 3.定義一個組合之后的函數(shù)
 function composeFn(...args) {
 // 3.1.拿到第一個函數(shù)的返回值
 let result = fns[0].apply(this, args)

 // 3.1.判斷傳入的函數(shù)個數(shù)
 if (fnsLen === 1) {
 // 如果傳入的函數(shù)個數(shù)為一個,直接將結(jié)果返回
 return result
 } else {
 // 如果傳入的函數(shù)個數(shù) >= 2
 // 依次將函數(shù)取出進行調(diào)用,將上一個函數(shù)的返回值作為參數(shù)傳給下一個函數(shù)
 // 從第二個函數(shù)開始遍歷
 for (let i = 1; i < fnsLen; i++) {
 result = fns[i].call(this, result)
 }

 // 將結(jié)果返回
 return result
 }
 }

 // 4.將組合之后的函數(shù)返回
 return composeFn
}

測試:

function double(num) {
 return num * 2
}
function square(num) {
 return num ** 2 
}

const composeFn = autoComposeFn(double, square)
const res = composeFn(10)
console.log(res) // 400

到此這篇關(guān)于JS函數(shù)式編程之純函數(shù)、柯里化以及組合函數(shù)的文章就介紹到這了,更多相關(guān)純函數(shù)、柯里化、組合函數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • JavaScript編程的10+最佳實踐解決方案

    JavaScript編程的10+最佳實踐解決方案

    在現(xiàn)代Web開發(fā)中,JavaScript已經(jīng)成為無法替代的核心技術(shù),在現(xiàn)代Web開發(fā)中,JavaScript已經(jīng)成為無法替代的核心技術(shù),本文將通過代碼示例詳細介紹一些實踐解決方案,感興趣的同學(xué)可以參考下
    2023-06-06
  • GoJs中標(biāo)題和縮略圖使用技巧

    GoJs中標(biāo)題和縮略圖使用技巧

    這篇文章主要為大家介紹了GoJs中標(biāo)題和縮略圖使用技巧詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-05-05
  • 微信小程序中實現(xiàn)車牌輸入功能

    微信小程序中實現(xiàn)車牌輸入功能

    我們都知道車牌是有一定規(guī)律的,本文實現(xiàn)了微信小程序中實現(xiàn)車牌輸入功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-05-05
  • JavaScript實現(xiàn)DOM對象選擇器

    JavaScript實現(xiàn)DOM對象選擇器

    這篇文章主要為大家詳細介紹了JavaScript實現(xiàn)DOM對象選擇器,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-09-09
  • webpack項目輕松混用css module的方法

    webpack項目輕松混用css module的方法

    這篇文章主要介紹了webpack項目輕松混用css module的方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-06-06
  • js監(jiān)控IE火狐瀏覽器關(guān)閉、刷新、回退、前進事件

    js監(jiān)控IE火狐瀏覽器關(guān)閉、刷新、回退、前進事件

    本節(jié)主要介紹了js監(jiān)控IE火狐瀏覽器關(guān)閉、刷新、回退、前進事件的方法
    2014-07-07
  • GoJs的文本繪圖模板TextBlock使用實例

    GoJs的文本繪圖模板TextBlock使用實例

    這篇文章主要為大家介紹了GoJs的文本繪圖模板TextBlock使用實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-04-04
  • JS 動態(tài)加載js文件和css文件 同步/異步的兩種簡單方式

    JS 動態(tài)加載js文件和css文件 同步/異步的兩種簡單方式

    下面小編就為大家?guī)硪黄狫S 動態(tài)加載js文件和css文件 同步/異步的兩種簡單方式。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09
  • HTML5實現(xiàn)微信拍攝上傳照片功能

    HTML5實現(xiàn)微信拍攝上傳照片功能

    這篇文章主要介紹了HTML5實現(xiàn)微信拍攝上傳照片功能,實現(xiàn)HTML5 Canvas手機拍攝,本地壓縮上傳圖片時遇到問題的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-04-04
  • JavaScript小技巧整理篇(非常全)

    JavaScript小技巧整理篇(非常全)

    這篇文章主要介紹了JavaScript小技巧整理篇(非常全)的相關(guān)資料,需要的朋友可以參考下
    2016-01-01

最新評論