You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无需Lodash:为函数实现柯里化与部分应用

Understanding Partial Application & Currying with Validator Functions

I'm new to functional programming and trying to wrap my head around partial application and currying. I want to figure out how to apply these concepts to the code below, specifically to avoid repeating array arguments and without relying on external libraries like Lodash or Ramda.

Here's my code (note: toggleValidatorsState uses ASP.NET's ValidatorEnable, so this runs in an ASP.NET environment):

var Page_Validators = [{ "controltovalidate": "Content_C002_txtAddress", "focusOnError": "t", "errormessage": "No Address Entered", "display": "Dynamic", "validationGroup": "ProfileControl", "initialvalue": "", "isvalid": true }, { "controltovalidate": "Content_C002_txtCity", "focusOnError": "t", "errormessage": "No City Entered", "display": "Dynamic", "validationGroup": "ProfileControl", "initialvalue": "", "isvalid": true }, { "controltovalidate": "Content_C002_drpState", "focusOnError": "t", "errormessage": "State Required", "display": "Dynamic", "validationGroup": "ProfileControl", "initialvalue": "", "isvalid": true }, { "controltovalidate": "Content_C002_txtZipcode", "focusOnError": "t", "errormessage": "No Zipcode Entered", "display": "Dynamic", "validationGroup": "ProfileControl", "initialvalue": "", "isvalid": true }, { "controltovalidate": "Content_C002_phoneNumberFull", "focusOnError": "t", "errormessage": "Missing Phone Number", "display": "Dynamic", "validationGroup": "ProfileControl", "initialvalue": "", "isvalid": true }, { "controltovalidate": "Content_C002_txtSupFullName", "focusOnError": "t", "errormessage": "No Name Entered", "display": "Dynamic", "validationGroup": "SupervisorControl", "initialvalue": "", "isvalid": true }, { "controltovalidate": "Content_C002_txtSupTitle", "focusOnError": "t", "errormessage": "No Title Entered", "display": "Dynamic", "validationGroup": "SupervisorControl", "initialvalue": "", "isvalid": true }, { "controltovalidate": "Content_C002_txtSupPhoneFull", "focusOnError": "t", "errormessage": "Missing Phone Number", "display": "Dynamic", "validationGroup": "SupervisorControl", "initialvalue": "", "isvalid": true }, { "controltovalidate": "Content_C002_txtSupEmail", "focusOnError": "t", "errormessage": "No Email Entered", "display": "Dynamic", "validationGroup": "SupervisorControl", "initialvalue": "", "isvalid": true }, { "controltovalidate": "Content_C002_SignatureField", "focusOnError": "t", "errormessage": "Signature Required", "display": "Dynamic", "validationGroup": "ProfileControl", "initialvalue": "", "isvalid": true }];

function filterArrayBy(arr, searchString) {
  return arr.filter(key => key.controltovalidate.toLowerCase().includes(searchString.toLowerCase()));
}

function toggleValidatorsState(arr, condition) {
  return arr.map(el => ValidatorEnable(el, condition));
}

const supervisorValidators = filterArrayBy(Page_Validators, "txtSup");
const disabledValidators = toggleValidatorsState(supervisorValidators, true);
console.log(disabledValidators);

My goal is to simplify these functions using partial application and currying, so I don't have to pass the array around repeatedly. How can I do this without external libraries?


Great question! Let's break down how to use currying and partial application here to clean up your code, no external libraries required. First, quick recap of the concepts to make sure we're on the same page:

  • Currying: Turning a multi-argument function into a sequence of single-argument functions.
  • Partial application: Locking in some arguments of a function to create a new function that only needs the remaining arguments.

Step 1: Curry filterArrayBy for reusability

Right now, your filterArrayBy takes the array first, then the search string. Let's flip that order and curry it—this lets us create specialized filter functions tied to specific search terms, which we can then apply to any array later.

// Curried version: takes searchString first, returns a function that accepts the array
const curriedFilterBy = (searchString) => (arr) => 
  arr.filter(key => key.controltovalidate.toLowerCase().includes(searchString.toLowerCase()));

Now we can create a reusable filter for supervisor validators without passing Page_Validators every time:

// Partial application: create a function that always filters for "txtSup"
const filterSupervisorValidators = curriedFilterBy("txtSup");
// Apply it to our target array once
const supervisorValidators = filterSupervisorValidators(Page_Validators);

Step 2: Curry toggleValidatorsState

We'll do the same for the toggle function—curry it so we can create reusable functions that set validators to a specific state (enabled/disabled), then apply those functions to any validator array.

// Curried version: takes condition first, returns a function that accepts the array
const curriedToggleValidators = (condition) => (arr) => 
  arr.map(el => ValidatorEnable(el, condition));

Now create a dedicated function for disabling validators:

// Partial application: create a function that disables any passed validators
const disableValidators = curriedToggleValidators(true);
// Apply it to our supervisor validators
const disabledValidators = disableValidators(supervisorValidators);

Step 3: Compose functions (optional but clean!)

Since we're leaning into functional patterns, we can even compose these curried functions to skip intermediate variables entirely. Let's build a single function that handles filtering and toggling in one go:

// Compose the two curried functions into a single reusable utility
const disableSupervisorValidators = (arr) => 
  disableValidators(filterSupervisorValidators(arr));

// Usage is now super concise:
const disabledValidators = disableSupervisorValidators(Page_Validators);

Or if you want to go all-in on currying, you can build a higher-order function that lets you create any validator toggler you need:

// Higher-order curried function: (condition) => (searchString) => (arr) => result
const createValidatorToggler = (condition) => (searchString) => (arr) => 
  curriedToggleValidators(condition)(curriedFilterBy(searchString)(arr));

// Create a specific function for disabling supervisor validators
const disableSupervisorValidators = createValidatorToggler(true)("txtSup");

// Usage:
const disabledValidators = disableSupervisorValidators(Page_Validators);

Quick note on your original code

I spotted a typo in toggleValidatorsState—you wrote condtion instead of condition! Fixed that in the curried version to prevent a runtime bug.


内容的提问来源于stack exchange,提问作者cpt-crunchy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:45:44