惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
腾讯CDC
博客园 - 聂微东
爱范儿
爱范儿
罗磊的独立博客
P
Proofpoint News Feed
博客园 - Franky
博客园 - 三生石上(FineUI控件)
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
酷 壳 – CoolShell
酷 壳 – CoolShell
Jina AI
Jina AI
Blog — PlanetScale
Blog — PlanetScale
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园 - 司徒正美
美团技术团队
MongoDB | Blog
MongoDB | Blog
WordPress大学
WordPress大学
A
About on SuperTechFans
I
InfoQ
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
H
Help Net Security
Microsoft Azure Blog
Microsoft Azure Blog
G
Google Developers Blog

博客园 - lzhdim

25个每个开发人员都应该掌握的JavaScript 数组方法 20260831 - 个人小作品更新 C#使用SQLite数据库例子 - 开源研究系列文章 20260830 - 个人小作品更新 20260829 - 个人小作品更新 13、JavaScript事件循环机制 - JavaScript学习系列文章 首款媲美分体水冷的一体水冷!微星CORELIQUID E15 360水冷散热器评测:目前为止 锐龙9 9950X3D最强性能释放 JavaScript常见的内存泄露问题 - JavaScript学习系列文章 C#开发的颜色取色器 - 开源研究系列文章 - 个人小作品 成长环境 - 我的闪存 提高 SQL 语句执行速度的方法 JavaScript安全最佳实践 关闭iPhone一些默认设置,让iPhone更流畅 20260814 - 个人小作品更新 JavaScript对象与元编程 20260812 - 个人小作品更新 JavaScript 模块化系统 Markdown 语法完全指南 C# 通过 Windows API 实现进程内存读写操作 C#开发的基于钩子技术监测键鼠事件的例子 - 开源项目研究文章 JavaScript异步编程的演进 近十年最帅风冷!酷冷至尊V8 ACE 3DHP散热器评测:单塔能干翻双塔 20260723 - 个人小作品更新 C# 中读取CPU、硬盘和内存温度 雷柏VT3s MAX鼠标评测:中小手型用户也没有被遗忘 顶尖性能的小号电竞鼠标来了 JavaScript 中的原型与继承 1分钟查清局域网所有IP 20260714 - 个人小作品更新 WorkBuddy 完整教程手册 专为AI而生的企业级QLC SSD!长江存储PE501 61.44TB评测:超过1PB的写入测试
JavaScript 函数进阶课题
lzhdim · 2026-08-03 · via 博客园 - lzhdim

一、函数是一等公民

在 JavaScript 中, 函数是"一等公民"(First-class Citizen). 这可不是随便给的称号,它意味着: 

1. 函数可以赋值给变量

2. 函数可以作为参数传递

3. 函数可以作为其他函数的返回值

// 1. 赋值给变量const greet = function(name) {  return `Hello, ${name}!`;};console.log(greet('Alice')); 
// 2. 作为参数传递function sayHello(greetingFn, name) {  console.log(greetingFn(name));}sayHello(greet, 'Bob'); 
// 3. 作为返回值function createGreeter(greeting) {  return function(name) {    return `${greeting}${name}!`;  };}const sayHi = createGreeter('Hi');console.log(sayHi('Charlie')); 

二、高阶函数

高阶函数(Higher-order Function)是指能够操作其他函数的函数, 它要么接受函数作为参数, 要么返回一个函数, 或者两者兼有. 2.1 接受函数作为参数:最常见的例子就是数组的方法了:

const numbers = [12345];
// map 是一个高阶函数,它接受一个函数作为参数const doubled = numbers.map(function(num) {  return num * 2;});console.log(doubled); 
// 用箭头函数更简洁const squared = numbers.map(num => num * num);console.log(squared); 

2.2 返回函数的函数:这种模式在创建特定功能的函数时特别有用:

function multiplyBy(factor) {  return function(number) {    return number * factor;  };}
const triple = multiplyBy(3);console.log(triple(5)); 
const double = multiplyBy(2);console.log(double(5)); 

2.3 创建验证器(应用示例):

function createValidator(testFn, errorMsg) {  return function(value) {    if (!testFn(value)) {      throw new Error(errorMsg);    }    return true;  };}
const isNumber = createValidator(  val => typeof val === 'number',  '必须是一个数字');
const isPositive = createValidator(  val => val > 0,  '必须是正数');
try {  isNumber('abc'); catch (e) {  console.error(e.message);}
try {  isPositive(-5); catch (e) {  console.error(e.message);}

三、闭包

闭包(Closure)是 JavaScript 中一个超级重要的概念. 简单说,闭包让函数可以"记住"创建时的环境.

function createCounter() {  let count = 0
  return function() {    count += 1;    return count;  };}
const counter = createCounter();console.log(counter()); console.log(counter()); console.log(counter()); 

这里的神奇之处在于, count 变量本该在 createCounter 执行完后就被销毁,但由于返回的函数引用了它, 它就活下来了!闭包的实际应用:

function createBankAccount(initialBalance) {  let balance = initialBalance;
  return {    depositfunction(amount) {      balance += amount;      return balance;    },    withdrawfunction(amount) {      if (amount > balance) {        throw new Error('余额不足');      }      balance -= amount;      return balance;    },    getBalancefunction() {      return balance;    }  };}
const account = createBankAccount(100);console.log(account.getBalance()); account.deposit(50);console.log(account.getBalance()); account.withdraw(75);console.log(account.getBalance()); // account.balance; // 无法直接访问,实现了真正的私有变量

四、函数柯里化

柯里化(Currying)是把接受多个参数的函数变换成接受单一参数(最初函数的第一个参数)的函数, 并且返回接受余下参数的新函数的技术.听起来有点绕, 我们来看一个例子: 

// 普通函数function add(a, b, c) {  return a + b + c;}
// 柯里化版本function curriedAdd(a) {  return function(b) {    return function(c) {      return a + b + c;    };  };}
console.log(add(123)); console.log(curriedAdd(1)(2)(3)); 

手动写柯里化函数太麻烦, 我们可以写一个通用的柯里化工具函数:

function curry(fn) {  return function curried(...args) {    if (args.length >= fn.length) {      return fn.apply(this, args);    } else {      return function(...args2) {        return curried.apply(this, args.concat(args2));      };    }  };}
// 使用const curriedAdd = curry(add);console.log(curriedAdd(1)(2)(3)); console.log(curriedAdd(12)(3)); console.log(curriedAdd(1)(23)); 

柯里化的实际应用:

// 日志函数function log(date, importance, message) {  console.log(`[${date.getHours()}:${date.getMinutes()}] [${importance}${message}`);}
// 柯里化版本const curriedLog = curry(log);
// 创建特定时间的日志函数const logNow = curriedLog(new Date());
// 创建重要级别的日志函数const logNowWarning = logNow('WARNING');
// 使用logNowWarning('内存泄漏检测'); 

柯里化的好处是我们可以创建一些基础函数, 然后通过部分应用参数来生成更具体的函数. 

五、函数组合

函数组合(Function Composition)是把多个函数组合成一个新函数的过程. 基本组合示例:

function compose(f, g) {  return function(x) {    return f(g(x));  };}
function double(x) {  return x * 2;}
function square(x) {  return x * x;}
const doubleThenSquare = compose(square, double);console.log(doubleThenSquare(5)); 
const squareThenDouble = compose(double, square);console.log(squareThenDouble(5)); 

多函数组合示例: 

function compose(...fns) {  return function(x) {    return fns.reduceRight((acc, fn) => fn(acc), x);  };}
function add1(x) {  return x + 1;}
function mul2(x) {  return x * 2;}
function sub3(x) {  return x - 3;}
const transform = compose(sub3, mul2, add1);console.log(transform(5)); // 计算过程:// 1. add1(5) => 6// 2. mul2(6) => 12// 3. sub3(12) => 9

六、偏函数应用

偏函数应用(Partial Application)是指固定一个函数的一些参数, 然后产生另一个更小元的函数. 看一个示例: 

// 简单的偏函数实现function partial(fn, ...presetArgs) {  return function(...laterArgs) {    return fn.apply(this, [...presetArgs, ...laterArgs]);  };}
// 使用function greet(greeting, name, punctuation) {  return `${greeting}${name}${punctuation}`;}
const sayHello = partial(greet, 'Hello');const sayHelloToJohn = partial(greet, 'Hello''John');
console.log(sayHello('Alice''!')); console.log(sayHelloToJohn('!!!')); 

柯里化: 每次只接受一个参数,返回一个新函数, 直到所有参数都收集完.

偏函数: 一次可以接受多个参数,固定这些参数, 返回一个需要剩余参数的函数.

七、省略不必要的参数, Point-Free风格

Point-Free 风格是一种编程风格,其中函数定义不显式地提到它们所操作的数据(即没有"点").我们来看个示例: 

// 非 Point-Freefunction isOdd(x) {  return x % 2 === 1;}const numbers = [12345];console.log(numbers.filter(x => isOdd(x)));
// Point-Freeconst isOdd = x => x % 2 === 1;console.log(numbers.filter(isOdd));

八、函子

函子是一个实现了 map 方法的对象, 它允许你在不直接操作值的情况下对值进行转换. 我们来看个简单的示例:

const plus1 = x => x + 1;[1, 2, 3].map(plus1); // [2, 3, 4]
class Box {  constructor(value) {    this.value = value;  }
  map(fn) {    return new Box(fn(this.value));  }
  toString() {    return `Box(${this.value})`;  }}
const result = new Box(5)  .map(x => x * 2)  .map(x => x + 1);
console.log(result.toString());