📞 第四章:函数基础

掌握函数的定义、调用和高级用法

4.1 函数声明 vs 函数表达式

函数声明

// 函数声明
function greet(name) {
    return `Hello, ${name}!`;
}

// 函数调用
const message = greet('John');
console.log(message); // Hello, John!

函数表达式

// 函数表达式
const greet = function(name) {
    return `Hello, ${name}!`;
};

// 函数调用
const message = greet('John');
console.log(message); // Hello, John!

// 匿名函数表达式
setTimeout(function() {
    console.log('Delayed message');
}, 1000);

区别

特性 函数声明 函数表达式
提升 会被提升 不会被提升
命名 必须有名字 可以是匿名的
使用场景 独立函数 作为值传递

4.2 箭头函数

箭头函数是 ES6 引入的语法糖,使函数定义更加简洁。

基本语法

// 基本语法
const greet = (name) => {
    return `Hello, ${name}!`;
};

// 单行箭头函数(自动返回)
const greet = (name) => `Hello, ${name}!`;

// 单个参数可以省略括号
const greet = name => `Hello, ${name}!`;

// 无参数
const sayHello = () => 'Hello!';

// 多个参数
const add = (a, b) => a + b;

this 陷阱

// 传统函数中的 this
const person = {
    name: 'John',
    greet: function() {
        console.log(`Hello, ${this.name}!`);
    }
};

person.greet(); // Hello, John!

// 箭头函数中的 this(继承外部作用域的 this)
const person2 = {
    name: 'John',
    greet: function() {
        setTimeout(() => {
            console.log(`Hello, ${this.name}!`); // this 指向 person2
        }, 1000);
    }
};

person2.greet(); // Hello, John!

箭头函数的最佳实践

4.3 参数处理

默认参数

// 默认参数
function greet(name = 'Guest') {
    return `Hello, ${name}!`;
}

greet(); // Hello, Guest!
greet('John'); // Hello, John!

// 复杂默认值
function createUser(name, options = {}) {
    const {
        age = 18,
        email = 'unknown@example.com'
    } = options;
    return { name, age, email };
}

剩余参数

// 剩余参数
function sum(...numbers) {
    return numbers.reduce((total, num) => total + num, 0);
}

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

// 混合使用普通参数和剩余参数
function logUser(name, ...details) {
    console.log(`Name: ${name}`);
    console.log(`Details: ${details}`);
}

logUser('John', 30, 'john@example.com');

解构赋值作为参数

// 解构赋值作为参数
function greet({ name, age }) {
    return `Hello, ${name}! You are ${age} years old.`;
}

greet({ name: 'John', age: 30 }); // Hello, John! You are 30 years old.

// 带默认值的解构参数
function createPerson({ name = 'Anonymous', age = 18 } = {}) {
    return { name, age };
}

createPerson(); // { name: 'Anonymous', age: 18 }
createPerson({ name: 'John' }); // { name: 'John', age: 18 }

4.4 作用域与闭包

块级作用域 vs 函数作用域

// 块级作用域(let 和 const)
if (true) {
    let blockVariable = 'block';
    const blockConstant = 'constant';
    var functionVariable = 'function';
}

console.log(blockVariable); // ReferenceError
console.log(blockConstant); // ReferenceError
console.log(functionVariable); // 'function'(函数作用域)

// 函数作用域
function myFunction() {
    var functionScoped = 'function scoped';
}

myFunction();
console.log(functionScoped); // ReferenceError

闭包

闭包是指函数能够访问其词法作用域之外的变量。
// 闭包示例
function createCounter() {
    let count = 0; // 私有变量
    
    return {
        increment: function() {
            count++;
            return count;
        },
        decrement: function() {
            count--;
            return count;
        },
        getCount: function() {
            return count;
        }
    };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.getCount()); // 1
console.log(count); // ReferenceError(count 是私有变量)

闭包的应用

动手练习

练习 1:函数声明与表达式

  1. 创建一个函数声明
  2. 创建一个函数表达式
  3. 比较它们的区别
  4. 测试函数提升

练习 2:箭头函数

  1. 将传统函数转换为箭头函数
  2. 测试箭头函数中的 this
  3. 使用箭头函数作为回调

练习 3:参数处理

  1. 使用默认参数
  2. 使用剩余参数
  3. 使用解构赋值作为参数

练习 4:闭包

  1. 创建一个闭包函数
  2. 实现数据私有化
  3. 创建一个函数工厂