Skip to content
Coding

好用的 JavaScript Library 使用筆記(1):Lodash — flow

_.flow() 是 Lodash 提供的一個函數組合方法,類似 chain 的概念,可以將多個函數串聯起來,形成一個新的函數。這個新函數會按照從左到右的順序執行傳入的函數,前一個函數的輸出會成為下一個函數的輸入。

實際應用場景:購物車結算

讓我們以購物車結算為例,比較傳統寫法與使用 flow 的差異。假設我們已經有以下幾個購物車結算時需要用到的函式了:

// 步驟 1: 計算商品總價 
function calculateSubtotal(cart) { 
  // ... 
} 
 
// 步驟 2: 處理折扣 
function applyDiscounts(subtotal, user) { 
  // ... 
} 
 
// 步驟 3: 處理折價券 
function applyCoupon(afterDiscount, coupon) { 
  // ... 
} 
 
// 步驟 4: 處理點數折抵 
function redeemPoints(afterCoupon, userPoints) { 
  // ... 
} 
 
// 步驟 5: 計算運費 
function calculateShipping(finalAmount) { 
  // ... 
}

傳統寫法(不使用 Flow)

function processCheckout(cart) { 
  const subtotal = calculateSubtotal(cart); 
   
  const discount = applyDiscounts(subtotal, cart.user); 
  const afterDiscount = subtotal - discount; 
   
  const couponDiscount = applyCoupon(afterDiscount, cart.coupon); 
  const afterCoupon = afterDiscount - couponDiscount; 
   
  const pointsUsed = redeemPoints(afterCoupon, cart.user.points); 
  const finalAmount = afterCoupon - pointsUsed; 
  const remainingPoints = cart.user.points - pointsUsed; 
   
  const shippingFee = calculateShipping(finalAmount); 
  const totalAmount = finalAmount + shippingFee; 
   
  return { 
    ...cart, 
    subtotal, 
    discount, 
    afterDiscount, 
    couponDiscount, 
    afterCoupon, 
    pointsUsed, 
    finalAmount, 
    remainingPoints, 
    shippingFee, 
    totalAmount 
  }; 
}

使用 Flow 的優雅寫法

// 購物車結算處理函數 
const processCheckout = _.flow([ 
  calculateSubtotal, 
  applyDiscounts, 
  applyCoupon, 
  redeemPoints, 
  calculateShipping 
]);

是不是看起來簡單很多呢?

兩種寫法的比較

傳統寫法的問題:

  • 所有邏輯都混在一個大函數裡
  • 變數名容易重複或混淆
  • 難以單獨測試某個步驟
  • 修改某個步驟可能影響其他部分
  • 可讀性較差,需要仔細閱讀才能理解流程

Flow 寫法的優勢:

  • 每個步驟都是獨立的函數,職責清晰
  • 函數名具有表達力,一眼就能看懂流程
  • 容易單獨測試每個步驟
  • 修改某個步驟不會影響其他部分
  • 可重用性高,函數可以在其他地方使用
  • 讀起來就像在描述業務流程

Flow vs FlowRight

Lodash 還提供了 flowRight 方法,它與 flow 的區別在於執行順序:

// flow: 從左到右執行 
const leftToRight = _.flow([addOne, multiplyByTwo]); 
console.log(leftToRight(3)); // (3 + 1) * 2 = 8 
 
// flowRight: 從右到左執行 
const rightToLeft = _.flowRight([addOne, multiplyByTwo]); 
console.log(rightToLeft(3)); // (3 * 2) + 1 = 7