函数
约 1885 字大约 6 分钟
2026-03-18
手写笔记



一、函数基础
1.1 函数定义方式
| 定义方式 | 语法示例 | 核心特点 |
|---|---|---|
| 函数声明 | function 函数名(参数) { 代码 } | 1. 会提升到脚本块顶部;2. 成为全局对象属性;3. 可在声明前调用 |
| 函数表达式 | let fn = function(参数) { 代码 } | 1. 不会提升;2. 不污染全局;3. 不能在声明前调用;4. 可匿名 |
1.2 函数本质与执行规则
- 函数本质:函数本身的代码不会直接运行,必须手动调用函数才会执行内部代码;
typeof 函数名→ 返回"function";- 函数内部声明变量:
- 不用
var声明 → 成为全局对象属性(污染全局); - 用
var声明 → 变量提升到所在函数顶部,外部不可访问。
- 不用
1.3 函数返回值
return关键字:- 函数运行后得到的结果,调用表达式的值就是函数返回值;
return会立即结束整个函数运行;return后不跟数据 → 返回undefined;- 函数无
return→ 函数末尾自动return undefined。
二、立即执行函数 (IIFE) 详解
2.1 核心作用
- 创建独立的函数作用域,隔离变量,避免全局污染(早期模块化的核心方案);
- 执行后立即销毁,不会在全局留下多余变量/函数。
2.2 语法规范
// 写法1(推荐):括号包裹函数体 + 调用括号传参
(function(a, b) {
let sum = a + b;
console.log(sum); // 内部变量,外部不可访问
})(10, 20);
// 写法2:括号包裹整个表达式
(function(a, b) {
console.log(a - b);
}(30, 15));
// 写法3:用 !/+/void 等运算符替代括号(兼容旧环境)
!function() {
console.log("立即执行");
}();2.3 关键特点
- 函数定义后立即执行,无需手动调用;
- 内部变量/函数不会暴露到全局;
- 可接收参数,也可返回值(如需外部使用,需赋值给全局变量);
- ES6 之前,是实现“模块化”的核心手段。
三、作用域与闭包
3.1 作用域核心概念
| 作用域类型 | 变量提升规则 | 全局污染 | 访问范围 |
|---|---|---|---|
| 全局作用域 | 提升到脚本顶部 | 是(成为 window 属性) | 所有地方可访问 |
| 函数作用域 | 提升到函数顶部 | 否(仅函数内可访问) | 自身 + 父级/全局作用域 |
| 块级作用域(ES6) | 无提升 | 否 | 仅块内可访问(let/const) |
3.2 作用域链与变量访问
- 全局作用域:只能访问自身作用域变量(含函数);
- 函数作用域:不仅能访问自身作用域变量(含参数),还能访问父级及以上所有作用域变量(含函数);
- 变量查找规则:从当前作用域向上查找,找到即停止,找不到则报错(
ReferenceError)。
3.3 闭包(Closure)
- 概念:内部函数 + 引用外部函数环境变量,是一种运行时现象;
- 本质:内部函数保留对外部函数作用域的引用,即使外部函数已执行完毕;
- 经典示例(立即执行函数 + 闭包):
let getNum = (function() { let num = 0; // 外部函数变量,被内部函数引用 return function() { num++; return num; }; })(); console.log(getNum()); // 1 console.log(getNum()); // 2(num 变量被闭包保留) - 作用:
- 私有化变量(避免全局污染);
- 延长变量生命周期;
- 实现模块化。
四、函数表达式与 this
4.1 函数表达式特殊点
- JS 中函数是引用类型数据,语法上可用于任何需要数据的地方;
- 将函数赋值给变量时,变量中存储的是函数的内存地址;
- 匿名函数表达式:无函数名,只能通过变量调用,适合临时使用的函数(如回调函数)。
4.2 this 关键字
- 全局作用域中:
this固定指向全局对象(浏览器中是window); - 函数作用域中:
this取值由函数调用方式决定:调用方式 this指向示例 直接调用 全局对象 fn();→ this = window对象调用 该对象 obj.fn();→ this = obj构造函数调用 新创建的对象 new Fn();→ this = 新对象立即执行函数 全局对象 (function(){})();→ this = window this无法被赋值(this = {}无效果)。
五、构造函数
5.1 概念与用法
- 概念:用于创建对象的函数(直接返回一个对象);
- 用法:
new 构造函数(参数); - 核心规则:
- 函数名使用大驼峰命名法(约定);
- 构造函数内部:
this指向新创建的对象,并自动返回该对象; - 若构造函数中手动写
return:- 返回原始类型 → 直接忽略,仍返回
this; - 返回引用类型 → 使用返回的对象;
- 返回原始类型 → 直接忽略,仍返回
- 所有对象最终都通过
new构造函数创建。
new.target:- 在函数中使用,返回当前构造函数;
- 若函数不是通过
new调用 → 返回undefined; - 常用于判断函数是否通过
new调用。
5.2 函数本质与包装类
- 函数本质是对象:
- 所有对象都通过
new Object()创建; - 所有函数都通过
new Function()创建; - 函数对象可以拥有自己的属性和方法。
- 所有对象都通过
- 包装类:JS 为增强原始类型功能,为
boolean/string/number分别创建了构造函数:Boolean/String/Number;- 语法上,将原始类型当作对象使用时(如
"abc".length),JS 会自动创建对应包装类对象,访问后自动销毁; - 本质:通过临时包装类对象来访问原始类型的“属性/方法”。
六、递归
6.1 递归概念
- 函数直接或间接调用自身。
- 注意:必须避免无限递归,否则会导致栈溢出(死循环不会报错,无限递归会栈溢出)。
6.2 执行栈与执行环境
- 执行栈:
- 任何代码执行都必须有执行环境,执行环境为代码提供支持;
- 执行环境存于执行栈中;
- 函数调用时创建新的函数执行环境,入栈;函数执行结束,执行环境销毁,出栈;
- 执行栈大小固定,超出会报错(栈溢出)。
- 尾递归:
- 定义:函数最后一条语句是调用函数,且调用不是表达式一部分 → 尾调用;若调用自身 → 尾递归;
- 优化:部分 JS 环境(如 Node.js)会对尾递归优化,销毁当前执行环境,避免栈溢出;
- 浏览器环境通常无尾递归优化。
- 递归例子:斐波拉契数列、阶乘、汉诺塔。
七、核心总结
- 函数定义:函数声明会提升,函数表达式/立即执行函数不会;立即执行函数(IIFE)是隔离变量、避免全局污染的核心方案;
- 作用域与闭包:函数作用域隔离变量,闭包让内部函数能访问外部函数变量,立即执行函数+闭包是早期模块化的核心;
this:调用方式决定this指向,立即执行函数的this默认指向全局对象;- 构造函数:
new关键字创建对象,this指向新对象,new.target判断调用方式; - 递归:函数调用自身需设置终止条件,避免栈溢出;尾递归在部分环境可优化。
