04函数基础
函数就是一段可重复调用的代码——给它一组输入,它按固定流程算出一个结果。
JavaScript 把函数当成"一等公民":能赋值、能传参、能返回、还能作为别人的输入或输出。
本课把三种写法、参数、返回值、作用域与闭包、this、高阶函数、IIFE
一次性讲清,让你从此能写出结构清晰、能复用的代码。
一、函数三种写法:声明 / 表达式 / 箭头
JS 函数有三种写法:function 声明(最经典,自动提升)、const 表达式
(要等赋值以后才能用)、const = () => { } 箭头函数(ES6 新增,语法最短,
不绑定自己的 this 和 arguments)。日常开发以箭头为主,
写法最干净;涉及 this 绑定或需要构造函数时才退回 function。
| 写法 | 是否提升 | this 怎么定 | 有 arguments 吗 | 典型场景 |
|---|---|---|---|---|
| function 声明 | ✓ 提升到顶端 | 看调用方式 | ✓ 有 | 主流程、构造函数、需要 this |
| const 表达式 | ✗ 必须先赋值 | 看调用方式 | ✓ 有 | 需要把函数当值传来传去 |
| 箭头函数 | ✗ 必须先赋值 | 看外层(词法) | ✗ 没有 | 回调、数组方法、闭包 |
打开浏览器的开发者工具(F12)→ Console 面板看输出
this、要做构造函数、要用 arguments——退回 function。
团队里风格统一就行,不必每个都争论。二、参数:默认值 / 剩余 / 解构
JS 函数参数非常灵活:可以设默认值(ES6),
可以用 ...args 把剩下的参数打包成数组(剩余参数),
还可以直接在形参里解构对象——像点菜一样精确告诉函数你需要哪些字段。
| 写法 | 语法 | 典型用途 |
|---|---|---|
| 默认参数 | function f(a, b = 10) { } | 参数不传时给一个合理兜底 |
| 剩余参数 | function f(first, ...rest) { } | 参数个数不确定(替代 arguments) |
| 解构参数 | function f({ name, age }) { } | 配置对象、用户信息等结构化输入 |
function fn({ page = 1, size = 10 } = {}, ...rest) 也不稀奇。三、返回值与提前结束
return 把结果交还给调用方,并立刻结束函数执行——
return 后面的代码全部跳过。函数没写 return 等价于返回 undefined。
箭头函数如果函数体只有一条表达式,可以省略 return 和大括号,单行写完。
{ } 和 return,否则返回 undefined——
const add = (a, b) => { a + b } 实际什么都不返回。四、作用域与闭包入门
作用域就是变量的"生存地盘":全局作用域(任何地方都能访问)、
函数作用域(函数体内)、块作用域({ } 内部,仅 let/const)。
闭包 = 函数能"记住"它定义时的变量环境——哪怕那个外层函数已经执行完毕,
内部函数依然能读到那些变量。这是 JS 最强大的特性之一。
| 作用域 | 由谁创建 | 能用什么变量 | 经典示例 |
|---|---|---|---|
| 全局作用域 | 页面加载 | 页面任意位置 | var a = 1 写在最外层 |
| 函数作用域 | 每次函数调用 | 参数 + 函数内声明的变量 | function f() { var x } |
| 块作用域 | { } 块 | 仅 let / const | if / for { let y } |
闭包让 n 留在内存里,不随 createCounter 执行完而消失
五、this 绑定(入门)
this 是函数内部的一个特殊变量,指向"调用这个函数的那个对象"。
普通函数的 this 取决于调用方式——不是定义位置;
箭头函数的 this 取决于定义时的外层,永远不变(也叫"词法 this")。
| 调用方式 | this 指向 | 示例 |
|---|---|---|
| 对象方法 | 调用它的那个对象 | obj.fn() → this = obj |
| 独立调用 | 非严格模式 → window;严格模式 → undefined | fn() |
| 箭头函数 | 定义时的外层 this | () => this 取外层 |
| new 调用 | 新创建的实例 | new Fn() → this = {} |
call/apply/bind 改 this);
② 普通函数的 this 看调用方式,不看定义位置——
var f = obj.fn; f(); 的 this 已经不再指向 obj,这是新手最常踩的坑。六、高阶函数:参数或返回值是函数
高阶函数 = 接收函数作为参数、或把函数作为返回值的函数。
数组三剑客 map / filter / reduce 全是这种思路:把"对每个元素做什么"这件事
交给调用方写,数组方法只负责遍历。这种"行为参数化"是 JS 写法优雅的关键。
| 方法 | 签名 | 作用 | 不修改原数组? |
|---|---|---|---|
| map | arr.map((item, i) => newItem) | 每个元素"变形",返回新数组 | ✓ |
| filter | arr.filter((item) => bool) | 留下满足条件的,返回新数组 | ✓ |
| reduce | arr.reduce((acc, item) => next, init) | 把数组"折叠"成一个值 | ✓ |
| forEach | arr.forEach((item) => { }) | 只遍历,不返回(返回 undefined) | — |
for 里 push 数组,几乎都能换成 map/filter/reduce。七、IIFE 与函数表达式应用
IIFE(Immediately Invoked Function Expression)= 定义后立刻执行的函数表达式。
写法:(function() { /* 代码 */ })();。最常见的用途是
创建一个独立作用域,避免变量污染全局。
ES6 之后有了 { } 块作用域,IIFE 的"造作用域"作用被削弱,
但解决 setTimeout 闭包陷阱依然是经典教学案例。
点按钮看输出
let 替代 var 就能避开 setTimeout 闭包陷阱——
for (let i = 0; i < 5; i++) 的 let 每次循环都创建独立绑定,
等价于 IIFE 的效果。但 IIFE 这个案例值得记住,因为面试常考、
也是理解闭包最直观的场景。八、小结
- JS 函数三种写法:function 声明(提升)/ const 表达式(不提升)/ 箭头(不绑 this),回调与数组方法优先用箭头。
- 参数三大增强:默认参数
b = 10/ 剩余参数...args/ 解构参数{ name, age },常一起出现。 return立刻结束函数并返回值;不写 return 等价于return undefined;箭头单行可省 return。- 作用域分全局 / 函数 / 块(
let/const);闭包 = 函数 + 定义时的变量环境,是防抖节流、模块化的基础。 - 普通函数 this 看调用方式(对象方法 → 对象,独立调用 → window);箭头函数 this 永远看外层——不能做构造函数。
- 高阶函数(map / filter / reduce)把行为参数化,链式调用是数组方法的杀手锏。
- IIFE = 立即执行的函数表达式,用于隔离作用域;经典用途是修 var + setTimeout 的闭包陷阱(用
let也能修)。
factorial(5) = 120(提示:用 reduce 或递归);
②写一个闭包累加器 const acc = makeAdder(10),调 acc(5) 返回 15;
③写一个 map 平方函数 const squareAll = arr => arr.map(n => n * n);
④用 IIFE 写一个独立作用域,往里面塞个 var pass = 'abc',外面访问不到。
全部用 console.log 验证。