Day-5-函数入门

Day 5: 函数入门

🎯 学习目标

  • 理解函数的概念和作用
  • 掌握函数的声明、调用和参数传递
  • 学会使用返回值和作用域
  • 理解回调函数的应用

💡 核心概念

什么是函数?

函数是一段可以重复使用的代码块,它接收输入(参数),进行处理,然后返回输出(返回值)。函数是编程中最基本的代码组织方式。

为什么需要函数?

1. 代码复用

// ❌ 重复代码
console.log("Hello, Alice!");
console.log("Hello, Bob!");
console.log("Hello, Charlie!");

// ✅ 使用函数
function greet(name) {
    console.log(`Hello, ${name}!`);
}
greet("Alice");
greet("Bob");
greet("Charlie");

2. 逻辑封装

将复杂的操作封装成函数,提高代码可读性。

3. 模块化开发

将程序分解为多个小函数,便于开发和维护。

📝 函数基础

1. 函数声明

// 函数声明(Function Declaration)
function functionName(parameter1, parameter2) {
    // 函数体
    return result;
}

// 示例
function add(a, b) {
    return a + b;
}

2. 函数表达式

// 函数表达式(Function Expression)
const functionName = function(parameter1, parameter2) {
    // 函数体
    return result;
};

// 示例
const multiply = function(a, b) {
    return a * b;
};

3. 箭头函数(ES6)

// 箭头函数(Arrow Function)
const functionName = (parameter1, parameter2) => {
    // 函数体
    return result;
};

// 简写(单行返回)
const subtract = (a, b) => a - b;

// 无参数
const sayHello = () => console.log("Hello!");

// 单参数(括号可省略)
const square = x => x * x;

🎮 参数详解

1. 默认参数

// 设置默认值
function greet(name = "World") {
    console.log(`Hello, ${name}!`);
}

greet();          // "Hello, World!"
greet("Alice");   // "Hello, Alice!"

2. 剩余参数(Rest Parameters)

// 使用 ... 收集所有参数
function sum(...numbers) {
    return numbers.reduce((total, num) => total + num, 0);
}

sum(1, 2, 3);           // 6
sum(1, 2, 3, 4, 5);     // 15

3. 解构参数

// 对象解构
function createUser({name, age, city}) {
    console.log(`${name}, ${age}岁,来自${city}`);
}

createUser({name: "张三", age: 25, city: "北京"});

// 数组解构
function swap([first, second]) {
    return [second, first];
}

🔄 返回值

1. return 语句

function calculate(price, quantity) {
    const total = price * quantity;
    return total;  // 返回结果
}

const result = calculate(10, 5);  // 50

2. 早期返回

// ✅ 好的实践:早期返回
function getUserRole(user) {
    if (!user) {
        return "Guest";  // 未登录返回 Guest
    }
    if (user.isAdmin) {
        return "Admin";
    }
    return "User";
}

// ❌ 不好的实践:深层嵌套
function getUserRole(user) {
    if (user) {
        if (user.isAdmin) {
            return "Admin";
        } else {
            return "User";
        }
    } else {
        return "Guest";
    }
}

3. 返回多个值

// 返回数组
function getMinMax(numbers) {
    return [Math.min(...numbers), Math.max(...numbers)];
}

const [min, max] = getMinMax([1, 2, 3, 4, 5]);

// 返回对象(更清晰)
function getPersonInfo(name) {
    return {
        firstName: name.split(" ")[0],
        lastName: name.split(" ")[1],
        length: name.length
    };
}

📦 作用域

1. 全局作用域 vs 局部作用域

const globalVar = "全局变量";

function testScope() {
    const localVar = "局部变量";
    console.log(globalVar);  // ✅ 可以访问
    console.log(localVar);   // ✅ 可以访问
}

console.log(globalVar);  // ✅ 可以访问
console.log(localVar);   // ❌ 报错:未定义

2. 变量遮蔽

const x = 10;  // 全局变量

function example() {
    const x = 20;  // 局部变量,遮蔽全局变量
    console.log(x);  // 20
}

example();
console.log(x);  // 10

3. 块级作用域(let 和 const)

function test() {
    if (true) {
        const blockScoped = "块级变量";
        let blockLet = "也是块级变量";
        var functionScoped = "函数级变量";
    }

    // console.log(blockScoped);  // ❌ 报错
    // console.log(blockLet);     // ❌ 报错
    console.log(functionScoped);  // ✅ 可以访问
}

🎯 实战示例

示例 1:表单验证函数

// 验证邮箱
function validateEmail(email) {
    const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return regex.test(email);
}

// 验证密码强度
function validatePassword(password) {
    if (password.length < 8) {
        return {valid: false, message: "密码至少8位"};
    }
    if (!/[A-Z]/.test(password)) {
        return {valid: false, message: "需要包含大写字母"};
    }
    if (!/[0-9]/.test(password)) {
        return {valid: false, message: "需要包含数字"};
    }
    return {valid: true, message: "密码强度合格"};
}

// 使用
const email = "user@example.com";
if (validateEmail(email)) {
    console.log("邮箱格式正确");
}

示例 2:DOM 操作封装

// 创建元素的辅助函数
function createElement(tag, options = {}) {
    const element = document.createElement(tag);

    // 设置属性
    if (options.id) element.id = options.id;
    if (options.className) element.className = options.className;
    if (options.text) element.textContent = options.text;
    if (options.html) element.innerHTML = options.html;

    // 添加事件监听
    if (options.onClick) {
        element.addEventListener('click', options.onClick);
    }

    return element;
}

// 使用
const button = createElement('button', {
    text: '点击我',
    className: 'btn btn-primary',
    onClick: () => alert('被点击了!')
});

document.body.appendChild(button);

示例 3:数据转换函数

// 格式化货币
function formatCurrency(amount, currency = 'CNY') {
    const symbols = {
        'CNY': '¥',
        'USD': '$',
        'EUR': '€'
    };
    return `${symbols[currency]}${amount.toFixed(2)}`;
}

// 格式化日期
function formatDate(date, format = 'YYYY-MM-DD') {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');

    return format
        .replace('YYYY', year)
        .replace('MM', month)
        .replace('DD', day);
}

// 使用
console.log(formatCurrency(99.9));              // "¥99.90"
console.log(formatDate(new Date()));            // "2026-03-07"

🔄 回调函数

什么是回调函数?

回调函数是作为参数传递给另一个函数的函数,在特定事件发生时被调用。

// 定时器回调
setTimeout(() => {
    console.log("1秒后执行");
}, 1000);

// 数组方法回调
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(num => num * 2);  // [2, 4, 6, 8, 10]

// 事件监听回调
button.addEventListener('click', function() {
    console.log("按钮被点击");
});

自定义回调函数

// 数据加载函数(模拟异步)
function loadData(callback) {
    console.log("开始加载数据...");
    setTimeout(() => {
        const data = {name: "张三", age: 25};
        callback(data);  // 数据加载完成后调用回调
    }, 1000);
}

// 使用
loadData(function(data) {
    console.log("数据加载完成:", data);
});

⚠️ 常见错误

1. 忘记 return

// ❌ 错误:没有 return
function add(a, b) {
    a + b;
}
console.log(add(2, 3));  // undefined

// ✅ 正确:加上 return
function add(a, b) {
    return a + b;
}
console.log(add(2, 3));  // 5

2. 修改全局变量

// ❌ 不好:修改全局变量
let count = 0;
function increment() {
    count++;
}

// ✅ 更好:使用参数和返回值
function increment(count) {
    return count + 1;
}

3. 参数过多

// ❌ 参数太多,难以维护
function createUser(name, age, email, phone, address, city) {
    // ...
}

// ✅ 使用对象参数
function createUser(options) {
    const {name, age, email, phone, address, city} = options;
    // ...
}

✍️ 练习任务

练习 1:基础函数

创建以下函数:

  1. celsiusToFahrenheit(celsius) – 摄氏度转华氏度
  2. calculateTriangleArea(base, height) – 计算三角形面积
  3. isEven(number) – 判断数字是否为偶数

练习 2:数组处理函数

创建以下函数:

  1. findMax(numbers) – 找出数组最大值
  2. filterPositive(numbers) – 过滤出正数
  3. reverseArray(arr) – 反转数组(不使用 reverse())

练习 3:字符串处理函数

创建以下函数:

  1. capitalize(str) – 首字母大写
  2. truncate(str, length) – 截断字符串并添加 "…"
  3. countWords(str) – 统计单词数量

🎓 今日挑战

项目:简易计算器

创建一个网页计算器,实现以下功能:

  1. 基本运算

    • 加法:add(a, b)
    • 减法:subtract(a, b)
    • 乘法:multiply(a, b)
    • 除法:divide(a, b)
  2. 高级运算

    • 幂运算:power(base, exponent)
    • 平方根:sqrt(number)
    • 取余:modulo(a, b)
  3. 辅助函数

    • 输入验证:validateInput(value)
    • 格式化结果:formatResult(number)
    • 错误处理:处理除零错误
  4. UI 界面

    • 创建按钮和显示区域
    • 绑定点击事件
    • 显示计算结果

提示

  • 使用函数封装每个运算
  • 使用对象存储计算历史
  • 使用回调函数处理按钮点击

💡 最佳实践

1. 单一职责原则

每个函数只做一件事,做好一件事。

2. 函数命名

  • 使用动词开头:getUser(), calculateTotal()
  • 命名要清晰:xuserData, temptemperature

3. 参数数量

  • 最好不超过 3-4 个参数
  • 参数过多时使用对象

4. 纯函数优先

纯函数:相同输入总是得到相同输出,无副作用。

// ✅ 纯函数
function add(a, b) {
    return a + b;
}

// ❌ 非纯函数(有副作用)
function addAndLog(a, b) {
    const result = a + b;
    console.log(result);  // 副作用
    return result;
}

📚 知识拓展

高阶函数

高阶函数是接收函数作为参数或返回函数的函数。

// 接收函数作为参数
function calculate(operation, a, b) {
    return operation(a, b);
}

calculate((x, y) => x + y, 2, 3);  // 5
calculate((x, y) => x * y, 2, 3);  // 6

// 返回函数
function createMultiplier(multiplier) {
    return function(x) {
        return x * multiplier;
    };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

double(5);  // 10
triple(5);  // 15

递归函数

函数调用自身。

// 计算阶乘
function factorial(n) {
    if (n <= 1) return 1;  // 基准情况
    return n * factorial(n - 1);  // 递归调用
}

factorial(5);  // 120

学习时间: 2026-03-07 13:05
难度: ⭐⭐⭐☆☆
预计用时: 2-3 小时
关键词: 函数, 参数, 返回值, 作用域, 回调函数, 箭头函数
相关标签: #04-函数