Skip to content

JavaScript 函数

函数是 JavaScript 中的基本构建块,用于封装可重复使用的代码。函数可以接收输入参数,执行特定任务,并返回结果。理解函数的概念和使用方法对于编写模块化、可维护的 JavaScript 代码至关重要。在本章节中,我们将深入学习 JavaScript 中的函数。

什么是函数

函数是一段可重复使用的代码块,用于执行特定任务。函数可以接收输入(参数),处理数据,并返回结果。函数的主要优势包括:

  1. 代码重用:避免重复编写相同代码
  2. 模块化:将复杂问题分解为小的、可管理的部分
  3. 可维护性:集中修改,影响所有调用点
  4. 可读性:通过函数名表达代码意图

函数的定义方式

1. 函数声明(Function Declaration)

javascript
function greet(name) {
    return "你好," + name + "!";
}

// 调用函数
console.log(greet("张三")); // "你好,张三!"

2. 函数表达式(Function Expression)

javascript
const greet = function(name) {
    return "你好," + name + "!";
};

// 调用函数
console.log(greet("李四")); // "你好,李四!"

3. 箭头函数(Arrow Function)- ES6

javascript
const greet = (name) => {
    return "你好," + name + "!";
};

// 简化写法
const greetSimple = (name) => "你好," + name + "!";

// 单参数可省略括号
const greetMinimal = name => "你好," + name + "!";

// 调用函数
console.log(greet("王五")); // "你好,王五!"

4. 构造函数方式

javascript
const greet = new Function("name", "return '你好,' + name + '!';");

console.log(greet("赵六")); // "你好,赵六!"

函数的组成部分

函数名

函数名用于标识和调用函数:

javascript
function calculateSum(a, b) {
    return a + b;
}

// 函数名应具有描述性
function getUserInfo() { /* ... */ }
function validateForm() { /* ... */ }
function formatDate() { /* ... */ }

参数(Parameters)

参数是函数接收的输入值:

javascript
// 单个参数
function square(x) {
    return x * x;
}

// 多个参数
function add(a, b) {
    return a + b;
}

// 无参数
function getCurrentTime() {
    return new Date();
}

返回值(Return Value)

函数可以返回值给调用者:

javascript
function multiply(a, b) {
    return a * b; // 返回计算结果
}

function greet(name) {
    console.log("你好," + name + "!"); // 无返回值,返回 undefined
}

const result = multiply(5, 3); // 15
const greeting = greet("张三"); // undefined

函数调用

基本调用

javascript
function sayHello() {
    return "Hello!";
}

const message = sayHello(); // 调用函数
console.log(message); // "Hello!"

带参数调用

javascript
function add(a, b) {
    return a + b;
}

const sum = add(5, 3); // 传递参数
console.log(sum); // 8

方法调用

javascript
const calculator = {
    add: function(a, b) {
        return a + b;
    },
    
    multiply(a, b) { // ES6 简写
        return a * b;
    }
};

const result1 = calculator.add(5, 3); // 8
const result2 = calculator.multiply(4, 2); // 8

参数处理

默认参数(ES6)

javascript
function greet(name = "朋友") {
    return "你好," + name + "!";
}

console.log(greet()); // "你好,朋友!"
console.log(greet("张三")); // "你好,张三!"

剩余参数(Rest Parameters)- ES6

javascript
function sum(...numbers) {
    let total = 0;
    for (let num of numbers) {
        total += num;
    }
    return total;
}

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

参数解构

javascript
// 对象解构参数
function createUser({ name, age, email }) {
    return {
        name: name,
        age: age,
        email: email,
        createdAt: new Date()
    };
}

const user = createUser({
    name: "张三",
    age: 25,
    email: "zhangsan@example.com"
});

// 数组解构参数
function processCoordinates([x, y]) {
    return {
        x: x,
        y: y,
        distance: Math.sqrt(x * x + y * y)
    };
}

const point = processCoordinates([3, 4]);
console.log(point.distance); // 5

函数作用域

全局作用域

javascript
const globalVar = "全局变量";

function example() {
    console.log(globalVar); // 可以访问全局变量
}

example();

函数作用域

javascript
function outer() {
    const outerVar = "外部变量";
    
    function inner() {
        const innerVar = "内部变量";
        console.log(outerVar); // 可以访问外部变量
        console.log(innerVar); // 可以访问内部变量
    }
    
    inner();
    // console.log(innerVar); // 错误:无法访问内部变量
}

outer();

块级作用域(ES6)

javascript
function example() {
    if (true) {
        const blockVar = "块级变量";
        let blockLet = "块级 let 变量";
        var functionVar = "函数变量"; // 函数作用域
    }
    
    // console.log(blockVar); // 错误:无法访问
    // console.log(blockLet); // 错误:无法访问
    console.log(functionVar); // 可以访问
}

闭包(Closure)

闭包是指函数可以访问其外部作用域中的变量:

javascript
function createCounter() {
    let count = 0;
    
    return function() {
        count++;
        return count;
    };
}

const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3

// 每个闭包都有独立的作用域
const counter2 = createCounter();
console.log(counter2()); // 1
console.log(counter());  // 4

闭包的实际应用

javascript
// 模块模式
const userManager = (function() {
    let users = [];
    
    return {
        addUser: function(user) {
            users.push(user);
        },
        
        getUsers: function() {
            return users;
        },
        
        getUserCount: function() {
            return users.length;
        }
    };
})();

userManager.addUser("张三");
userManager.addUser("李四");
console.log(userManager.getUsers()); // ["张三", "李四"]
console.log(userManager.getUserCount()); // 2

高阶函数

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

接收函数作为参数

javascript
function calculate(a, b, operation) {
    return operation(a, b);
}

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

function multiply(a, b) {
    return a * b;
}

console.log(calculate(5, 3, add));      // 8
console.log(calculate(5, 3, multiply)); // 15

返回函数

javascript
function createMultiplier(factor) {
    return function(number) {
        return number * factor;
    };
}

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

console.log(double(5)); // 10
console.log(triple(5)); // 15

立即执行函数表达式(IIFE)

IIFE 是定义后立即执行的函数:

javascript
// 基本形式
(function() {
    console.log("IIFE 执行了");
})();

// 带参数的 IIFE
(function(name) {
    console.log("你好," + name + "!");
})("张三");

// 返回值的 IIFE
const result = (function(a, b) {
    return a + b;
})(5, 3);

console.log(result); // 8

递归函数

递归函数是调用自身的函数:

javascript
// 计算阶乘
function factorial(n) {
    if (n <= 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

console.log(factorial(5)); // 120

// 斐波那契数列
function fibonacci(n) {
    if (n <= 1) {
        return n;
    }
    return fibonacci(n - 1) + fibonacci(n - 2);
}

console.log(fibonacci(10)); // 55

函数的 this 关键字

[this](file:///C:/Workspace/Coding/WebProjects/tutorials-web/node_modules/typescript/lib/lib.es5.d.ts#L78-L82) 关键字的值取决于函数的调用方式:

全局上下文

javascript
console.log(this); // 浏览器中是 window,Node.js 中是 global

对象方法

javascript
const person = {
    name: "张三",
    greet: function() {
        return "你好,我是" + this.name;
    }
};

console.log(person.greet()); // "你好,我是张三"

箭头函数中的 this

javascript
const person = {
    name: "李四",
    greet: function() {
        // 普通函数
        console.log("普通函数:" + this.name);
        
        // 箭头函数
        const arrowFunction = () => {
            console.log("箭头函数:" + this.name);
        };
        
        arrowFunction();
    }
};

person.greet();
// 输出:
// 普通函数:李四
// 箭头函数:李四

函数方法

call() 方法

javascript
function greet(greeting, punctuation) {
    return greeting + ",我是" + this.name + punctuation;
}

const person = { name: "张三" };

const result = greet.call(person, "你好", "!");
console.log(result); // "你好,我是张三!"

apply() 方法

javascript
function sum(a, b, c) {
    return a + b + c;
}

const numbers = [1, 2, 3];
const result = sum.apply(null, numbers);
console.log(result); // 6

bind() 方法

javascript
function greet(greeting) {
    return greeting + ",我是" + this.name;
}

const person = { name: "李四" };
const boundGreet = greet.bind(person);

console.log(boundGreet("你好")); // "你好,我是李四"

函数的最佳实践

1. 函数命名

javascript
// 好的命名:动词开头,描述性
function calculateTotal() { /* ... */ }
function validateForm() { /* ... */ }
function getUserInfo() { /* ... */ }
function formatDate() { /* ... */ }

// 不好的命名
function doIt() { /* ... */ }
function process() { /* ... */ }
function handle() { /* ... */ }

2. 函数长度控制

javascript
// 保持函数简短,单一职责
function calculateTax(income) {
    if (income <= 5000) return 0;
    if (income <= 10000) return (income - 5000) * 0.1;
    return 500 + (income - 10000) * 0.2;
}

// 复杂逻辑分解为多个函数
function processOrder(order) {
    validateOrder(order);
    calculateTotal(order);
    applyDiscount(order);
    saveOrder(order);
}

3. 参数处理

javascript
// 使用对象参数处理多个参数
function createUser({ name, age, email, phone }) {
    // 参数验证
    if (!name || !email) {
        throw new Error("姓名和邮箱是必需的");
    }
    
    return {
        name,
        age: age || 0,
        email,
        phone: phone || "",
        createdAt: new Date()
    };
}

4. 错误处理

javascript
function divide(a, b) {
    if (b === 0) {
        throw new Error("除数不能为零");
    }
    return a / b;
}

try {
    const result = divide(10, 0);
} catch (error) {
    console.log("错误:" + error.message);
}

实际应用示例

事件处理函数

javascript
// 通用事件处理函数
function createEventHandler(handler, context = null) {
    return function(event) {
        try {
            handler.call(context, event);
        } catch (error) {
            console.error("事件处理错误:", error);
        }
    };
}

// 使用示例
const button = document.getElementById("myButton");
const handleClick = createEventHandler(function(event) {
    console.log("按钮被点击了");
}, this);

button.addEventListener("click", handleClick);

数据处理函数

javascript
// 通用数据处理管道
function createPipeline(...functions) {
    return function(data) {
        return functions.reduce((result, func) => func(result), data);
    };
}

// 数据处理函数
function validate(data) {
    if (!data || typeof data !== "object") {
        throw new Error("无效数据");
    }
    return data;
}

function transform(data) {
    return {
        ...data,
        processedAt: new Date(),
        processed: true
    };
}

function log(data) {
    console.log("处理数据:", data);
    return data;
}

// 创建处理管道
const processData = createPipeline(validate, transform, log);

// 使用示例
try {
    const result = processData({ name: "张三", age: 25 });
    console.log("处理结果:", result);
} catch (error) {
    console.error("处理失败:", error.message);
}

函数式编程工具

javascript
// 函数式编程工具函数
const utils = {
    // 映射函数
    map: function(array, transform) {
        const result = [];
        for (let i = 0; i < array.length; i++) {
            result.push(transform(array[i], i));
        }
        return result;
    },
    
    // 过滤函数
    filter: function(array, predicate) {
        const result = [];
        for (let item of array) {
            if (predicate(item)) {
                result.push(item);
            }
        }
        return result;
    },
    
    // 归约函数
    reduce: function(array, reducer, initialValue) {
        let accumulator = initialValue;
        for (let item of array) {
            accumulator = reducer(accumulator, item);
        }
        return accumulator;
    }
};

// 使用示例
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const evenNumbers = utils.filter(numbers, n => n % 2 === 0);
console.log("偶数:", evenNumbers); // [2, 4, 6, 8, 10]

const squares = utils.map(numbers, n => n * n);
console.log("平方:", squares); // [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

const sum = utils.reduce(numbers, (acc, n) => acc + n, 0);
console.log("总和:", sum); // 55

总结

JavaScript 函数的核心要点:

  1. 定义方式:函数声明、函数表达式、箭头函数、构造函数
  2. 组成部分:函数名、参数、返回值、函数体
  3. 调用方式:基本调用、方法调用、构造调用
  4. 参数处理:默认参数、剩余参数、参数解构
  5. 作用域:全局作用域、函数作用域、块级作用域
  6. 高级特性:闭包、高阶函数、递归、IIFE
  7. this 关键字:不同调用方式下的 this 值
  8. 函数方法:call()、apply()、bind()
  9. 最佳实践:命名规范、长度控制、错误处理

函数是 JavaScript 编程的核心,掌握函数的使用对于编写高质量的 JavaScript 代码至关重要。在下一章节中,我们将学习 JavaScript 的作用域。

本站内容仅供学习和研究使用。