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

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
}

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

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

几乎都建立在函数之上。

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

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

记住一句话就够了

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

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

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

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

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

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

相关推荐
用户2181697049301 小时前
Gin (六) mysql的操作 gin操作mysql
后端
weixin_397574091 小时前
AgentRAG与ReAct推理链:从检索增强到推理增强
前端·react.js·前端框架
想要狠赚笔的小燕2 小时前
vue项目的入口文件是什么 main.js还是index.html,他俩有啥区别
前端·javascript
AI打工人2 小时前
Python并发编程:多线程与多进程实战指南
后端
Jiude2 小时前
AI面对真机调试也束手无策?我将方法论形成了一套SKILL 🛠️🤖
前端·后端·测试
千云2 小时前
AI Coding 落地探索日志·实践篇·提效操作指南
后端
之歆2 小时前
Day02_ES6+ 核心特性深度解析:现代 JavaScript 开发的基石
前端·javascript·es6
DigitalOcean2 小时前
DigitalOcean 的 AI 推理路由器是如何构建的
后端·aigc·agent
问心无愧05132 小时前
ctf show web入门71
android·前端·笔记