← JavaScript return语句 JavaScript函数参数 →

JavaScript函数

原创 2026-03-12 JavaScript 已有人查阅

JavaScript函数指南:从基础到进阶的实用教程

一、函数到底是什么

函数是JavaScript中最基础也最重要的概念之一。函数就是一段可以重复使用的代码块,用来完成特定的任务。它接收一些输入(参数),经过处理后返回一个输出(返回值)。有了函数,我们就能把复杂的大型程序拆分成一个个小而 manageable 的模块。

在的开发中,我见过太多人一开始就陷入复杂逻辑的泥潭,就是因为没有用好函数。把代码拆分成函数,就像整理房间一样,东西分门别类放好,找起来才方便。

二、声明函数的方式

2.1 函数声明(基本方式)

使用function关键字来声明函数,这是最传统也最常用的方式:

function 计算总和(数字1, 数字2) {
    return 数字1 + 数字2;
}

let 结果 = 计算总和(15, 27);
console.log(结果); // 输出42

函数名的命名规则需要留意:

  • 区分大小写(getData和getdata是两个不同的函数)

  • 可以用字母、下划线_、美元符号$开头

  • 不能包含空格

  • 不能用JavaScript的保留字(如if、for、return等)

2.2 函数表达式

函数可以赋值给变量,这种方式叫函数表达式:

const 乘法计算 = function(数字1, 数字2) {
    return 数字1 * 数字2;
};

let 乘积 = 乘法计算(6, 7);
console.log(乘积); // 输出42

个人经验分享:函数声明和函数表达式有个重要区别——函数声明会被提升(hoisting),可以在声明前调用;函数表达式不会提升,必须先定义后使用。早期我因为不了解这个区别,踩过不少坑:

// 这样可以
console.log(声明函数(5)); // 输出10
function 声明函数(x) {
    return x * 2;
}

// 这样会报错
console.log(表达式函数(5)); // TypeError: 表达式函数 is not a function
const 表达式函数 = function(x) {
    return x * 2;
};

三、函数的参数

函数可以接收零个或多个参数:

// 无参数
function 获取当前时间() {
    return new Date().toLocaleDateString();
}

// 多个参数
function 创建用户(姓名, 年龄, 邮箱) {
    return {
        name: 姓名,
        age: 年龄,
        email: 邮箱,
        createdAt: "2026-03-12"
    };
}

let 新用户 = 创建用户("王小明", 28, "alan@ebingou.cn");
console.log(新用户);

四、函数的方法

JavaScript的函数有一些内置方法,可以用来控制函数的执行方式。

4.1 call()方法

call()方法可以指定函数内部的this指向,参数一个个传递:

function 介绍() {
    console.log("我是" + this.姓名 + ",今年" + this.年龄 + "岁");
}

let 人员 = {
    姓名: "李华",
    年龄: 25
};

介绍.call(人员); // 输出: 我是李华,今年25岁

4.2 apply()方法

apply()和call()功能类似,区别在于参数以数组形式传递:

function 介绍(城市, 职业) {
    console.log(`${this.姓名}来自${城市},职业是${职业}`);
}

let 用户 = { 姓名: "张明" };

介绍.apply(用户, ["上海", "前端开发"]);
// 输出: 张明来自上海,职业是前端开发

4.3 bind()方法

bind()不会立即执行函数,而是返回一个绑定了this的新函数:

function 打招呼() {
    console.log("你好," + this.名字);
}

let 人物 = { 名字: "陈静" };
let 打招呼绑定 = 打招呼.bind(人物);

打招呼绑定(); // 输出: 你好,陈静

个人见解:这三个方法中,我平时用得最多的是bind(),特别是在React类组件中处理事件绑定。call()和apply()在需要临时改变this指向时很有用,但现在开发中很多场景已经被箭头函数替代了。

4.4 toString()方法

这个方法返回函数的源码字符串:

function 测试函数(a, b) {
    return a + b;
}

console.log(测试函数.toString());
// 输出: function 测试函数(a, b) { return a + b; }

调试的时候偶尔会用上,但日常开发中用得不多。

五、函数的各种类型

5.1 箭头函数

ES6引入的箭头函数写法更简洁,而且不绑定自己的this:

// 传统写法
let 数字 = [1, 2, 3, 4, 5];
let 平方1 = 数字.map(function(项) {
    return 项 * 项;
});

// 箭头函数写法
let 平方2 = 数字.map(项 => 项 * 项);

console.log(平方2); // [1, 4, 9, 16, 25]

为什么用箭头函数

  • 语法简洁,特别适合简单的回调函数

  • 不创建自己的this,继承外层this,解决了传统函数this指向混乱的问题

  • 不能用作构造函数,没有arguments对象

5.2 回调函数

把一个函数作为参数传给另一个函数,这个传进去的函数就是回调函数:

function 处理数据(数据, 回调) {
    console.log("开始处理数据...");
    let 处理结果 = 数据.toUpperCase();
    回调(处理结果);
}

function 显示结果(内容) {
    console.log("处理结果:", 内容);
}

处理数据("hello world", 显示结果);
// 输出:
// 开始处理数据...
// 处理结果: HELLO WORLD

在工作中回调函数无处不在,比如事件监听、定时器、异步请求等。

5.3 匿名函数

没有名字的函数就是匿名函数,作为临时使用的函数:

// 赋值给变量
let 打招呼 = function() {
    console.log("你好啊");
};

// 作为回调
setTimeout(function() {
    console.log("3秒后执行");
}, 3000);

// 立即执行
(function() {
    console.log("定义完就执行");
})();

5.4 立即执行函数(IIFE)

定义完就立即执行的函数,主要用来创建独立作用域:

(function() {
    let 私有变量 = "只有内部能访问";
    console.log("IIFE执行了");
})();

// console.log(私有变量); // 报错,访问不到

个人经验:在ES6模块普及之前,IIFE是模拟模块化、避免变量污染全局环境的常用手段。现在有了let、const和模块系统,IIFE用得少了,但在一些老项目或特定场景下还是会遇到。

5.5 嵌套函数(闭包)

函数内部定义函数,内部函数可以访问外部函数的变量:

function 创建计数器(初始值) {
    let 计数 = 初始值 || 0;
    
    function 增加() {
        计数 += 1;
        return 计数;
    }
    
    return 增加;
}

let 我的计数器 = 创建计数器(10);
console.log(我的计数器()); // 11
console.log(我的计数器()); // 12

这就是闭包的典型例子——内部函数记住了它被创建时的环境变量。很多源码(https://www.ebingou.cn/yuanma/)里都用这种模式来封装私有状态。

六、函数的优势

6.1 代码复用

写一次,用多次:

function 计算折扣(价格, 折扣率) {
    return 价格 * (1 - 折扣率);
}

let 衣服价格 = 计算折扣(200, 0.2);
let 鞋子价格 = 计算折扣(500, 0.15);
let 帽子价格 = 计算折扣(80, 0.1);

6.2 模块化

把相关功能组织在一起:

// 用户相关功能
function 用户登录(账号, 密码) { /* ... */ }
function 用户登出() { /* ... */ }
function 获取用户信息() { /* ... */ }

// 订单相关功能
function 创建订单(商品列表) { /* ... */ }
function 取消订单(订单号) { /* ... */ }
function 查询订单(订单号) { /* ... */ }

6.3 易于调试

错误定位更精准:

function 第一步处理(数据) {
    // 如果这里出错,知道是第一步的问题
    return 数据.trim();
}

function 第二步处理(数据) {
    // 如果这里出错,知道是第二步的问题
    return 数据.toUpperCase();
}

function 第三步处理(数据) {
    // 如果这里出错,知道是第三步的问题
    return 数据.split('');
}

6.4 可读性

好名字的函数就是的注释:

// 不友好的写法
let a = b * c;
let d = a + e;
let f = d / g;

// 友好的写法
let 税后收入 = 月收入 * 税率;
let 可支配收入 = 税后收入 - 固定支出;
let 日均预算 = 可支配收入 / 30;

七、函数的实践

7.1 函数职责单一

一个函数只做一件事:

// 不推荐
function 处理用户(用户) {
    // 验证用户
    if (!用户.姓名) return "姓名不能为空";
    
    // 保存到数据库
    db.save(用户);
    
    // 发送邮件
    email.send(用户.邮箱, "欢迎注册");
    
    // 记录日志
    log.write("新用户注册");
}

// 推荐
function 验证用户(用户) { /* ... */ }
function 保存用户(用户) { /* ... */ }
function 发送欢迎邮件(邮箱) { /* ... */ }
function 记录注册日志(用户) { /* ... */ }

7.2 使用有意义的函数名

函数名要能看出做什么:

// 不清晰
function f(a, b) {
    return a * b;
}

// 清晰
function 计算矩形面积(宽度, 高度) {
    return 宽度 * 高度;
}

7.3 合理使用默认参数

function 创建用户(姓名, 年龄 = 18, 角色 = "访客") {
    return {
        name: 姓名,
        age: 年龄,
        role: 角色
    };
}

console.log(创建用户("张三")); // 年龄默认18,角色默认访客
console.log(创建用户("李四", 25, "管理员"));

7.4 提前返回处理错误情况

function 获取用户详情(用户ID) {
    if (!用户ID) return { error: "用户ID不能为空" };
    if (用户ID < 0) return { error: "用户ID无效" };
    
    // 正常逻辑
    return { id: 用户ID, name: "用户" + 用户ID };
}

本节课程知识要点

  • 函数名要见名知意

  • 每个函数只做一件事

  • 处理异常情况优先于主逻辑

  • 善用默认参数和提前返回

  • 根据场景选择合适的函数类型(普通函数、箭头函数、回调等)

八、本节课程小结

函数是JavaScript编程的基石。从简单的函数声明到复杂的闭包,从传统的function到现在的箭头函数,函数的形式在变,但核心思想不变——把代码组织成可复用的单元。

回顾一下核心内容:

  1. 声明方式:函数声明(提升)、函数表达式(不提升)

  2. 方法:call()、apply()、bind()、toString()

  3. 类型:箭头函数、回调函数、匿名函数、IIFE、嵌套函数

  4. 优势:复用、模块化、可读性、易调试

  5. 实践:职责单一、命名规范、提前返回

建议:新手学函数,不要急着把所有花样都学会。先把function关键字用熟,理解参数和返回值,知道怎么调用。然后再慢慢接触箭头函数、闭包这些进阶概念。写代码的时候多想想:这段逻辑能不能抽成函数?这个函数名字够不够清楚?这样练上几个月,函数这块就算真正入门了。

← JavaScript return语句 JavaScript函数参数 →
分享笔记 (共有 篇笔记)
验证码:
微信公众号