最近正在學習阮一峰老師的es6(第三版)教材,在學到第七章《函式的擴展》中的箭頭函式嵌套時,文中提到了一個關于“管道機制”的示例,文中源代碼如下:
//es6(第三版)教材中的管道機制源代碼:
const pipeline = (...funcs) =>
val => funcs.reduce((a, b) => b(a), val);
const plus1 = a => a + 1;
const mult2 = a => a * 2;
const addThenMult = pipeline(plus1, mult2);
addThenMult(5);
下面為我對這段代碼的理解分析:
一、這段代碼中用到了2個主要知識點:
1、es6中的新特性:rest引數(即上面代碼中pipeline函式的形參…funcs,它表示pipeline函式的形參是一個包含多個函式的函式陣列,funcs則為陣列名),形式為:…變數名,用于獲取函式的多個引數,類似于之前的arguments物件,rest引數搭配的變數是一個陣列,該變數可以將多個引數放入其中,因為rest引數中的變數代表一個陣列,所以陣列特有的方法都可以用于這個變數,
2、陣列物件的reduce()方法(這也是實作管道機制的核心技術):
reduce() 方法接收一個函式作為回呼函式,reduce()方法為陣列中的每一個元素(從左到右)依次執行這個回呼函式,最終計算為一個值,
語法:arrayObject.reduce(function(prev, currentItem, currentIndex, arrayObject), initialValue)
引數:
●prev:必需,表示陣列中前一個元素呼叫reduce() 方法回呼函式后的回傳值,或者初始值 initialValue;
●currentItem:必需,表示當前正在呼叫reduce() 方法回呼函式的陣列元素;
●currentIndex:可選,表示當前正在呼叫reduce() 方法回呼函式的陣列元素的索引,若提供了 initialValue值,則索引為0,否則索引為1;
●arrayObject:可選,當前正在呼叫reduce() 方法回呼函式元素所屬的陣列物件(即呼叫reduce()的陣列);
●initialValue:可選,傳遞給此reduce() 方法回呼函式的初始值,作為第一次呼叫回呼函式時的第一個引數的值, 如果沒有提供初始值,則將使用陣列中的第一個元素, 在沒有初始值的空陣列上呼叫 reduce 將報錯,
關于initialValue引數作用的進一步說明:回呼函式第一次執行時,prev 和currentItem的取值有兩種情況:如果呼叫reduce()時提供了initialValue,則prev取值為initialValue,currentItem取陣列中的第一個元素;如果沒有提供 initialValue,那么prev取陣列中的第一個元素,currentItem取陣列中的第二個元素,如果沒有提供initialValue,reduce 會從索引1的陣列元素開始執行回呼函式,跳過第0個索引,如果提供initialValue,則從索引0開始,如果陣列為空且沒有提供initialValue,會拋出TypeError ,如果陣列僅有一個元素,并且沒有提供initialValue, 或者有提供initialValue但是陣列為空,那么此唯一值將被回傳并且回呼函式不會被執行,
關于reduce()方法的運用實體,可以參照MDN這篇文章:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce,會更有利于幫助理解這個方法的用途,以下為MDN部分截圖:

二、管道機制(pipeline):(MDN中也稱“功能型函式管道”)即前一個函式的輸出是后一個函式的輸入,管道機制類似于jQuery中的鏈式編程,以return的形式持續操作,
三、這段代碼實作的功能為:讓一個數字先與1相加,得出的結果然后再與2相乘,最后回傳計算后的結果,
四、經過對上面代碼的一番思考,我根據自己的理解將上面代碼的引數表示稍作了一點語意化的改動,讓我更清晰的理解這段代碼的運行機制:
const pipeline = (...funcs) =>
num => {
console.log( num);
return funcs.reduce((prev, fn) => fn(prev), num);
}
const plus1 = num=> num + 1;
const mult2 = lastresult => lastresult * 2;
const addThenMult = pipeline(plus1, mult2);
console.log(addThenMult(5)) ; //12
下面為這段代碼的具體注釋詳解:
const pipeline = (...funcs) =>
num => {
//列印這個形參 num看一下, num就是傳遞給reduce方法里回呼函式的初始值
console.log( num);
//funcs陣列呼叫reduce()方法,這時,初始值num就是reduce回呼函式中的第一個形參prev,而此時reduce回呼函式中的第二個形參fn則代表funcs陣列里的第一個函式,根據這個回呼函式的函式體:(prev, fn) => fn(prev)執行,首先將初始值num(即prev)傳遞給funcs陣列里的第一個函式(即fn())作為實參并進行第一個函式的呼叫,第一個函式的運算結果(即lastresult)得出后緊接著把這個結果再傳給funcs陣列里第二個函式作為第二個函式的實參并進行呼叫,第二個函式的運算結果得出后緊接著再傳給第三個函式作為第三個函式的實參并進行呼叫,以此類推,,,,,,直到funcs陣列中的最后一個函式元素執行完畢后,pipeline函式回傳的函式的回傳值就是reduce()方法的回傳值,而reduce()方法的回傳值就是funcs陣列中最后一個函式引數執行回呼函式后回傳的值,
return funcs.reduce((prev, fn) => fn(prev), num);
}
const plus1 = num => num + 1;
const mult2 = lastresult => lastresult * 2;
//實參plus1函式對應形參funcs陣列中的第一項元素,也就是pipeline函式的第一個形參
//實參mult2函式對應形參funcs陣列中的第二項元素,也就是pipeline函式的第二個形參
const addThenMult = pipeline(plus1, mult2);
//這里的實參“5”就是傳遞給pipeline()函式return回的addThenMult函式中funcs陣列呼叫reduce()方法后的回呼函式的初始值 num, 5會先作為plus1函式的實參傳入并執行plus1函式,結果為5+1=6;然后再將這個結果6(即lastresult)傳遞給mult2函式作為mult2函式的實參并執行mult2函式,結果為6*2=12,
console.log(addThenMult(5))
//所以最后devtools中上面兩處console.log()列印出的結果分別為:
>>5
>>12
五、最后,再附上一張MDN中對于管道機制的一個示例,也可以幫助更好的理解管道機制的實作原理:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/180433.html
標籤:JavaScript
上一篇:ThreeJS 3d模型簡介
下一篇:javascript匿名函式自執行 (function(window,document,undefined){})(window,document);
