CodeRoadMap
首页路线题库资源库文章社区
CodeRoadMap

程序员的学习成长路线图。内容免费开放,登录后可同步路线图与课时进度。

由 程序员柏风 独立维护 · 关于作者

学习

  • 路线图
  • 课程
  • 面试题
  • 文章
  • 我

更多

  • 资源
  • 社区
  • 关于作者
  • 内容说明

© 2026 CodeRoadMap

津ICP备2026012044号-1·津公网安备12011002026155号·coderoadmap@126.com
JavaScript 核心/课时/函数与作用域
RawBlame
课时目录12 节

JavaScript 核心

  1. 01JavaScript 是什么
  2. 02类型与变量
  3. 03运算符与类型转换
  4. 04条件与循环
  5. 05函数与作用域
  6. 06数组与常用方法
  7. 07对象与 JSON
  8. 08DOM 与事件
  9. 09异步 Promise 与 async/await
  10. 10ES Module 与 npm 概览
  11. 11错误处理与调试
  12. 12综合练习与下一步

函数与作用域

声明、箭头函数、闭包入门。

35 分钟

函数与作用域

这一课你将能做到

  1. 声明函数并用参数接收输入、用 return 给出结果
  2. 解释什么叫「作用域」(变量在哪可见),并能指出一段代码里谁能看见谁
  3. 看懂箭头函数的基本写法,知道和普通函数在调用方式上的一点差别

为什么要学

把「评级」「校验年龄」复制粘贴三次,改规则就要改三处。
函数把一段逻辑打包,起个名字,需要时调用——这是编程最重要的习惯之一。

作用域则决定「名字在哪能用」。搞不清就会出现:外面改不到里面的变量、或者误用全局变量互相踩脚。

先建立图像

函数像榨汁机:
  输入(参数:苹果) → 处理 → 输出(return:果汁)
不写 return,默认得到 undefined(「没明确送出东西」)

作用域人话:变量的「可见范围」。
在函数里用 const/let 声明的变量,外面一般拿不到——这是好事,避免名字打架。

外层:site
  └─ 函数 greet 内:message
       greet 可读 site(往外找)
       外层不能读 message(进不去)

跟着做

步骤 1:函数声明

// 函数声明:有名字,可被调用
function add(a, b) {
  return a + b; // 把结果送出去
}
console.log(add(2, 3)); // 5
console.log(add);       // 函数本身(还没调用)

记住:add 是函数值;add() 才是调用并执行。

步骤 2:函数表达式与箭头函数

const add2 = function (a, b) {
  return a + b;
};

const add3 = (a, b) => {
  return a + b;
};

// 只有一句返回时可以更短:
const add4 = (a, b) => a + b;

console.log(add2(1, 2), add3(1, 2), add4(1, 2));

初学:三种都能算;团队项目里箭头函数很常见。
注意:箭头函数没有自己的 this(进阶话题);DOM 回调里用箭头通常更省心。

步骤 3:作用域演示

const site = "CodeRoadMap"; // 外层

function greet(name) {
  const message = "欢迎," + name; // 只在函数里
  return message + " @ " + site;   // 里面可以读外面的 site
}

console.log(greet("同学"));
// console.log(message); // 打开会报错:外面没有 message

你应看到欢迎语;若取消注释最后一行,会得到 ReferenceError——这正好说明作用域在起作用。

步骤 4:默认参数与提前校验

function labelScore(score, unit = "分") {
  if (!Number.isFinite(score)) {
    return "无效分数";
  }
  return `${score}${unit}`;
}

console.log(labelScore(95));        // 95分
console.log(labelScore(95, " pts")); // 95 pts
console.log(labelScore(NaN));       // 无效分数

默认参数减少「调用方漏传」时的尴尬;无效输入仍应用卫语句拦住。

步骤 5:接到按钮(把函数当积木)

保存为 js-functions.html:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>函数</title>
</head>
<body>
  <input id="a" type="text" value="2" />
  <input id="b" type="text" value="3" />
  <button type="button" id="sum">相加</button>
  <p id="out"></p>
  <script>
    const add = (x, y) => x + y;

    function readNumber(id) {
      return Number(document.getElementById(id).value);
    }

    document.getElementById("sum").addEventListener("click", () => {
      const x = readNumber("a");
      const y = readNumber("b");
      const out = document.getElementById("out");
      if (!Number.isFinite(x) || !Number.isFinite(y)) {
        out.textContent = "请输入有效数字";
        return;
      }
      out.textContent = "结果:" + add(x, y);
    });
  </script>
</body>
</html>

点击「相加」应看到结果。注意:readNumber 和 add 各管一件事——小函数更好测、更好改。

步骤 6:闭包混个脸熟(计数器)

function makeCounter() {
  let n = 0; // 被内部函数「记住」
  return function () {
    n = n + 1;
    return n;
  };
}

const c = makeCounter();
console.log(c()); // 1
console.log(c()); // 2
const c2 = makeCounter();
console.log(c2()); // 1 —— 另一份独立的 n

人话:内层函数还能访问外层变量,即使外层已经执行完——这叫闭包。
先会用计数器直觉即可,不必一次啃完所有理论。

讲清楚要点

  1. 因为要把逻辑复用,所以抽函数:参数进、return 出。
  2. 因为 return 立刻结束函数,所以 return 后面的代码不会跑。
  3. 因为函数内 const/let 有块/函数作用域,所以外面访问不到,反而减少命名冲突。
  4. 因为同样输入应尽量同样输出,所以少在函数里偷偷改全局变量(更「纯」更好查)。
  5. 因为 add 与 add() 不同,所以把函数当值传递时不要多余加括号(事件监听常传函数引用)。
  6. 因为参数太多难记,所以超过 3~4 个考虑收成一个对象参数(对象课会用到)。

你可能会懵的地方

  • () 忘了写会怎样?
    add 是函数本身;add() 才是调用。没括号等于「把函数当值传递」,不一定执行。

  • 闭包是什么?
    函数「记住」外层变量的能力。步骤 6 的计数器就是最小例子。

  • 箭头函数能不能当所有写法的替代?
    多数回调可以。若你需要传统的 this 绑定或 arguments,再用普通函数——进阶时再查 MDN。

  • 函数提升(hoisting)
    function foo(){} 声明在文件后面有时仍能调用;const foo = ()=>{} 则不行。现代代码更推荐表达式/箭头并注意声明顺序。

错法对照

错法问题正解
复制粘贴同一段逻辑改一处漏三处抽函数
依赖隐式全局变量难查 bug参数传入或明确模块内变量
函数又长又多职责难测难读拆小函数
该 return 却只 console.log调用方拿不到结果需要结果就 return
事件里写成 fn() 立刻执行绑的是返回值传 fn 或 () => fn()

自测三问

  1. return 的作用是什么?不写会怎样?
  2. 函数内部的 const 外面为什么常常访问不到?
  3. add 和 add() 的区别?

小结一句话

函数打包输入→处理→输出;用作用域限制变量可见范围;先会声明/箭头/return,再慢慢熟悉闭包。

延伸

  • MDN:函数
  • MDN:闭包
  • 下一课:数组与常用方法。
加载本节练习…
← 上一课条件与循环下一课 →数组与常用方法