一、为什么要学习函数?

浏览器执行代码时,需要你给出非常详细的指令。如果所有逻辑都写成零散的语句,成百上千行代码会变得难以维护和复用。

函数、方法和对象,正是解决这一问题的核心工具。它们能帮你:

  • 组织代码结构,让逻辑更清晰
  • 复用重复代码,减少冗余
  • 控制执行时机,只在需要时运行代码

二、函数基础:定义与调用

1. 什么是函数?

函数是一组语句的集合,用于执行特定任务。它有两个核心优势:

  1. 代码复用:把重复执行的逻辑封装起来,避免复制粘贴相同代码
  2. 延迟执行:函数内的代码不会随页面加载自动执行,只有被 “调用” 时才会运行

2. 函数的声明与调用

(1)基础语法结构

javascript

运行

// 函数声明:定义一个简单的打招呼函数
function sayHello() {
  // 函数体:执行任务的代码块
  document.write('Hello!');
}

// 函数调用:触发函数执行
sayHello(); // 控制台/页面输出:Hello!
  • function:关键字,用于声明函数
  • sayHello:函数名,用于后续调用(需见名知意)
  • ():参数列表(无参数时为空)
  • {}:函数体,包含要执行的代码
(2)带参数的函数

当函数需要外部数据才能完成任务时,可以通过形参接收输入:

javascript

运行

// 声明带形参的函数:计算矩形面积
function getArea(width, height) {
  // 形参 width 和 height 在函数内的行为和变量完全一致
  return width * height;
}

// 调用函数时传入实参:3和5分别对应width和height
let wallArea = getArea(3, 5); 
console.log(wallArea); // 输出:15
  • 形参:函数声明时括号内的变量,仅在函数内部有效
  • 实参:调用函数时传入的具体值,会被赋值给对应的形参
(3)带返回值的函数

函数执行后,可以通过 return 关键字将结果返回给调用它的代码:

javascript

运行

function calculateArea(width, height) {
  // 函数内部定义变量存储计算结果
  let area = width * height;
  // return 关键字:返回结果,并立即结束函数执行
  return area;
}

// 用变量接收函数的返回值
let wallOne = calculateArea(3, 5); // 结果:15
let wallTwo = calculateArea(8, 5); // 结果:40

console.log(wallOne, wallTwo); // 输出:15 40

⚠️ 注意:return 执行后,函数会立即停止,后续代码不会被执行。


三、函数进阶:表达式与匿名函数

1. 函数声明 vs 函数表达式

(1)函数声明(Function Declaration)

我们前面写的 function area() {} 就是函数声明,它的特点是:

  • 有明确的函数名
  • 存在函数提升:可以在声明之前调用

javascript

运行

// 声明函数
function area(width, height) {
  return width * height;
}

// 可以在声明前调用(提升特性)
let size = area(3, 4); 
console.log(size); // 输出:12
(2)函数表达式(Function Expression)

将函数赋值给变量,这种写法称为函数表达式。如果省略函数名,就是匿名函数

javascript

运行

// 匿名函数表达式:函数没有名字,存储在变量area中
let area = function(width, height) {
  return width * height;
};

// 调用方式和普通函数一致
let size = area(3, 4); 
console.log(size); // 输出:12

⚠️ 注意:函数表达式没有提升特性,必须先声明再调用。

2. 立即调用函数表达式(IIFE)

如果希望函数定义后立即执行一次,可以使用 IIFE(Immediately Invoked Function Expression,读作 “iffy”):

javascript

运行

// IIFE 写法:匿名函数 + 立即执行括号
let area = (function() {
  let width = 3;
  let height = 2;
  return width * height;
})();

console.log(area); // 输出:6
核心作用:
  • 隔离作用域:IIFE 内部的变量不会污染全局环境
  • 一次性执行:适合初始化、配置等只需要运行一次的逻辑
  • 避免命名冲突:多个脚本文件中同名变量互不影响(jQuery 早期广泛使用这种模式)

四、变量作用域:局部与全局

变量的声明位置决定了它的作用域(可访问范围),这是 JS 中最容易踩坑的知识点之一。

1. 局部变量(函数作用域)

在函数内部用 var/let/const 声明的变量,只能在该函数内部访问,称为局部变量:

javascript

运行

function getArea(width, height) {
  // 局部变量:仅在函数内部有效
  let area = width * height;
  return area;
}

getArea(3, 2); 
console.log(area); // 报错:area is not defined(外部无法访问)
  • 局部变量在函数执行时创建,执行结束后立即销毁
  • 不同函数内的同名局部变量不会冲突

2. 全局变量

在函数外部声明的变量,或声明时省略 var/let/const 的变量,会成为全局变量:

javascript

运行

// 全局变量:脚本任何地方都能访问
let wallSize = 0;

function getArea(width, height) {
  wallSize = width * height; // 直接修改全局变量
  return wallSize;
}

getArea(3, 2); 
console.log(wallSize); // 输出:6(外部可以访问)

⚠️ 全局变量的风险:

  1. 内存占用:页面加载期间一直驻留内存,影响性能
  2. 命名冲突:多个脚本中同名全局变量会相互覆盖
  3. 调试困难:全局变量的修改难以追踪

3. 作用域最佳实践

  • 优先使用局部变量,减少全局变量声明
  • 必要时用 IIFE 封装代码,隔离作用域
  • 声明变量时必须加 let/const,避免意外创建全局变量

五、实战:用函数封装一个面积计算器

结合前面的知识点,我们写一个完整的面积计算器,支持矩形和圆形:

javascript

运行

// 1. 矩形面积计算(带参数和返回值)
function calculateRectangleArea(width, height) {
  if (width <= 0 || height <= 0) {
    return '错误:宽和高必须大于0';
  }
  return width * height;
}

// 2. 圆形面积计算(带参数和返回值)
function calculateCircleArea(radius) {
  if (radius <= 0) {
    return '错误:半径必须大于0';
  }
  return Math.PI * radius * radius;
}

// 3. 用IIFE封装初始化逻辑(一次性执行)
(function() {
  let wallWidth = 4;
  let wallHeight = 5;
  let wallArea = calculateRectangleArea(wallWidth, wallHeight);
  console.log(`墙的面积:${wallArea} 平方米`);

  let circleRadius = 3;
  let circleArea = calculateCircleArea(circleRadius);
  console.log(`圆形的面积:${circleArea.toFixed(2)} 平方米`);
})();

运行结果:

plaintext

墙的面积:20 平方米
圆形的面积:28.27 平方米

六、总结与进阶方向

核心知识点回顾

表格

概念 关键要点
函数声明 function 关键字定义,支持提升,可在声明前调用
函数表达式 函数赋值给变量,无提升,必须先声明再调用
形参 / 实参 形参是占位符,实参是实际传入的值
return 返回结果并结束函数,无 return 时返回 undefined
作用域 局部变量仅函数内有效,全局变量作用于整个脚本
IIFE 匿名函数立即执行,用于隔离作用域

进阶学习方向

  1. 箭头函数:ES6 新增的 () => {} 语法,更简洁的函数写法
  2. 闭包:函数嵌套时,内部函数访问外部函数变量的特性
  3. 回调函数:将函数作为参数传递,实现异步逻辑(如事件监听)
  4. 函数柯里化:将多参数函数拆分为多个单参数函数,实现参数复用

💡 写在最后:函数是 JS 的 “第一公民”,从简单的工具函数到复杂的业务逻辑,几乎所有 JS 代码都离不开函数。理解函数的声明、调用、作用域和执行机制,是你从入门到进阶的必经之路。

更多推荐