古法编程秘籍(三):为什么需要函数?因为程序员讨厌重复劳动

Hi!这里是 JustHappy 这是专为编程初学者准备的专栏,哈哈,AI 时代更需要我们返璞归真!我们继续秘籍修炼之旅吧,这期我们来聊聊函数这个概念,函数不是语法糖,是程序员对"重复劳动"的反击:把一串动作起个名字,复杂藏起来,一句调用就能反复用。参数让同一函数适配不同人,返回值把结果带出来,回调/高阶函数把规则也能传递。记住:重复三次,就该抽函数。

上一篇我们讲了模块化。

模块化解决的是:代码放哪里、怎么分组、怎么别乱放。

但还有一个更致命的问题:同一件事你要写多少遍?

重复劳动这件事,写着写着就会失控

假设你在做一个网站,需要给用户发欢迎消息。

最开始只有一个用户,你可能就这么写:

js 复制代码
console.log('欢迎张三')

后来来了第二个:

js 复制代码
console.log('欢迎张三')
console.log('欢迎李四')

第三个:

js 复制代码
console.log('欢迎张三')
console.log('欢迎李四')
console.log('欢迎王五')

那如果有一万个用户呢?

难道你真打算写一万行 console.log

这时候你会很自然地产生一个想法:

把重复的动作取个名字,以后只叫名字就行。

js 复制代码
function welcome() {
  console.log('欢迎用户')
}

以后要欢迎谁,你就"重复调用",而不是"重复粘贴":

js 复制代码
welcome()
welcome()
welcome()

函数最早、最朴素的意义就是这个:反复做的事,别反复写。

函数不是语法,它是在帮你"止损"

教材会说:函数是可重复调用的代码块。

没错,但太表面了。

函数真正解决的问题是:别让人类重复劳动

因为机器最擅长重复。

而人最不擅长重复(尤其是"改十个地方,漏一个地方"的那种重复)。

你想象一下:欢迎语现在要改成更正式一点,比如从"欢迎张三"改成"欢迎你,张三同学"。

  • 你如果写了一万行,那你就要改一万行
  • 你如果抽了函数,那你改一行就够了

所以函数看起来像在"偷懒",其实是在给未来的自己减刑

函数本质上是在封装动作:给一串步骤起名字

你平时看到的登录可能就一句:

js 复制代码
login()

但它背后通常是一串步骤(而且还会越长越长):

  1. 校验账号密码
  2. 请求服务器
  3. 生成或拿到 token
  4. 保存登录状态
  5. 跳转首页 / 拉取用户信息

这些细节,调用者根本不想知道。

调用者只关心两件事:

  • 我能不能用(接口怎么调)
  • 能不能成(结果是什么 / 出错怎么提示)

所以函数的本质可以粗暴总结成一句话:

给一组动作起名字,把复杂藏起来。

软件工程一直在做同一件事:给复杂的东西起名字

随着项目变大,程序员每天都在干一件事:

把一坨复杂逻辑,起个更像人话的名字。

于是你会看到一堆"看起来很简单"的调用:

js 复制代码
login()
logout()
createOrder()
payOrder()
sendMessage()

这些名字背后,可能是几百行、几千行。

但对调用者来说,最好是这样的体验:

我只关心"做什么",不关心"怎么做"。

这其实就是软件工程一个很核心的思路:

关注接口,隐藏实现。

函数为什么会越来越复杂?因为需求越来越不客气

最开始函数只能做"固定动作",比如 welcome()

但很快你就会发现:张三要欢迎,李四也要欢迎。

你当然不想写 welcomeZhangSan()welcomeLiSi() 这种东西。

于是出现了参数:把"变化的部分"交给调用者传进来。

js 复制代码
function welcome(name) {
  console.log(`欢迎 ${name}`)
}

welcome('张三')
welcome('李四')

再后来,很多函数不只是执行动作,还要把结果交出来:

js 复制代码
function sum(a, b) {
  return a + b
}

const total = sum(10, 20)

然后你又会碰到更真实的场景:比如请求接口。

js 复制代码
request('/user')

请求完成以后怎么办?

  • 有的页面要渲染用户信息
  • 有的页面要跳转
  • 有的页面要缓存起来下次用

不同场景不同处理方式,于是你开始把"未来要做的事"也当成参数传进去------这就是回调。

js 复制代码
request('/user', (data) => {
  renderUser(data)
})

再再后来,你会发现:数据能传,逻辑也能传。

于是你开始把"规则"传给函数------这就是高阶函数(函数接收函数)。

js 复制代码
users.filter((u) => u.age > 18)

你还会发现:有些配置长期不变,有些参数经常变化。

比如域名不变、路径变;或者"请求方式/默认头"不变、"具体接口"变。

于是你会喜欢先"配好",再"执行"------这就是柯里化那类思路(先固定一部分参数)。

js 复制代码
const requestWithBase = (baseUrl) => (path) => fetch(baseUrl + path)
const api = requestWithBase('https://api.example.com')
api('/user')

再后来你又发现:函数执行完就结束了,但我想让它记住一些状态,比如次数、缓存、用户信息......

于是闭包出现了(让行为携带状态):

js 复制代码
function createCounter() {
  let count = 0
  return () => ++count
}

const next = createCounter()
next() // 1
next() // 2

再往后,项目大了、bug 多了、同事也多了,你开始追求:

同样输入,永远同样输出(更好测、更好推导)------这就是纯函数那套味道。

最后你又会回到一个朴素结论:一个函数只做一件事最舒服。

于是你把 format()validate()save() 这些小函数组合起来:

js 复制代码
const submit = (data) => save(validate(format(data)))

你看,函数越学越多,其实不是函数变花哨了,是需求在变难。

函数只是一路把你带到"软件工程"的门口。

你以为你在学函数,其实你在学抽象

很多人以为函数就是:

js 复制代码
function add(a, b) {
  return a + b
}

但真实情况是:函数是软件工程里最基础的抽象单位。

后面你接触到的参数、返回值、回调、高阶函数、闭包、纯函数、组合......

几乎都建立在函数之上。

甚至你以为很"高级"的那些东西:设计模式、框架、架构思想......

很多都能追溯到这里:怎么把复杂变简单,怎么把变化关进笼子里。

记住一句话就够了

函数从来不是为了让代码显得高级。

它存在的理由只有一个:让程序员少写重复劳动

你可以把它当成一个写代码的"警报器":

  • 重复一次:还能忍
  • 重复两次:开始不爽
  • 重复三次:差不多该抽函数了

因为机器负责重复,人负责思考。

下一篇我们聊参数:为什么同一个函数能处理无数情况。

相关推荐
AlienZHOU3 小时前
AI Coding 时代下,我的技术面试实践分享
前端·后端·面试
狗头大军之江苏分军5 小时前
《潮水漫过十七岁》开学了
后端
苏三说技术6 小时前
如何看待GPT-6在UP主众测中碾压夺冠?它是现在最强大模型吗?
后端
mldong6 小时前
一份 JSON,一条能跑的审批流:把报销流程送上工作流引擎
后端·架构
wno7046 小时前
Spring Boot WebFlux增删改查
java·spring boot·后端
Captaincc6 小时前
AI用量v0.1.11更新发布 新增 jusage doctor 诊断指令 托盘展示token 和余额 新增 AutoClaw 支持
前端·后端·vibecoding
aramae7 小时前
模拟实现strlen()函数 (C语言)
c语言·开发语言·后端
计算机魔术师8 小时前
德国Wiki被黑后两周,OpenAI终于把模型失控的账本摊开了
前端
kyriewen8 小时前
我让 AI 当面试官面了我一轮:第 3 个追问我就卡住了(附 10 道追问清单)
前端·面试·ai编程
IT_陈寒8 小时前
Python的GIL把我坑惨了,多线程跑得比单线程还慢
前端·人工智能·后端