JS从入门到精通--函数

91 阅读3分钟

函数的基本概念

函数是一段可以重复调用的代码块,用于执行特定的任务。JavaScript 中的函数是一等公民,这意味着函数可以像其他数据类型(如数字、字符串、对象等)一样被赋值、传递和返回。

一、函数的定义

JavaScript 中定义函数的方式有多种:

  1. 函数声明(Function Declaration)

    function greet(name) {
        return `Hello, ${name}!`;
    }
    
    • 函数声明会被提升(hoisted),即在代码执行前,函数声明会被提升到作用域的顶部,因此可以在函数声明之前调用。
  2. 函数表达式(Function Expression)

    const greet = function(name) {
        return `Hello, ${name}!`;
    };
    
    • 函数表达式不会被提升,必须在定义后才能调用。
  3. 箭头函数(Arrow Function) (ES6+)

    const greet = (name) => {
        return `Hello, ${name}!`;
    };
    
    • 箭头函数是函数表达式的简写形式,具有更简洁的语法。
    • 箭头函数没有自己的 this,它的 this 继承自外层作用域。
  4. 立即执行函数表达式(IIFE)

    (function() {
        console.log("This is an IIFE!");
    })();
    
    • IIFE 会在定义后立即执行,通常用于创建一个独立的作用域,避免变量污染全局作用域。

二、函数的参数与返回值

参数
  • 函数可以接受零个或多个参数。

  • 参数是函数内部的局部变量,用于接收外部传入的值。

  • 默认参数(ES6+):

    function greet(name = "Guest") {
        return `Hello, ${name}!`;
    }
    console.log(greet()); // 输出: Hello, Guest!
    
返回值
  • 函数可以通过 return 语句返回一个值。

  • 如果没有 return 语句,函数默认返回 undefined

    function add(a, b) {
        return a + b;
    }
    console.log(add(2, 3)); // 输出: 5
    

三、作用域与闭包

作用域(Scope)
  • 作用域决定了变量的可见性和生命周期。

  • JavaScript 有全局作用域、函数作用域和块级作用域(ES6+)。

    let globalVar = "I'm global"; // 全局作用域
    
    function foo() {
        let localVar = "I'm local"; // 函数作用域
        console.log(globalVar); // 可以访问全局变量
    }
    
    if (true) {
        let blockVar = "I'm block scoped"; // 块级作用域
    }
    
闭包(Closure)
  • 闭包是指函数能够访问其词法作用域中的变量,即使函数在其词法作用域之外执行。

  • 闭包常用于创建私有变量或实现函数柯里化。

    function createCounter() {
        let count = 0; // 私有变量
        return function() {
            count++;
            return count;
        };
    }
    
    const counter = createCounter();
    console.log(counter()); // 输出: 1
    console.log(counter()); // 输出: 2
    

四、高阶函数

高阶函数是指接受函数作为参数或返回函数的函数。高阶函数是函数式编程的核心概念之一。

函数作为参数
function operate(a, b, operation) {
    return operation(a, b);
}

function add(x, y) {
    return x + y;
}

console.log(operate(2, 3, add)); // 输出: 5
函数作为返回值
function createMultiplier(multiplier) {
    return function(number) {
        return number * multiplier;
    };
}

const double = createMultiplier(2);
console.log(double(5)); // 输出: 10

五、递归函数

递归函数是指函数调用自身的过程。递归常用于解决分治问题,如遍历树结构、计算阶乘等。

示例:计算阶乘
function factorial(n) {
    if (n === 0 || n === 1) {
        return 1;
    }
    return n * factorial(n - 1);
}

console.log(factorial(5)); // 输出: 120
递归的注意事项
  • 递归需要有终止条件,否则会导致无限递归,最终栈溢出。
  • 递归的性能可能不如循环,但对于某些问题(如树形结构遍历)更直观。

六、箭头函数的特点

箭头函数是 ES6 引入的一种简洁的函数语法,但它与普通函数有一些重要区别:

  1. 没有自己的 this

    • 箭头函数的 this 继承自外层作用域。
    • 普通函数的 this 取决于调用方式。
    const obj = {
        name: "Alice",
        greet: function() {
            setTimeout(() => {
                console.log(`Hello, ${this.name}!`); // 输出: Hello, Alice!
            }, 1000);
        }
    };
    obj.greet();
    
  2. 没有 arguments 对象

    • 箭头函数没有自己的 arguments 对象,但可以通过剩余参数(...args)获取参数列表。
  3. 不能作为构造函数

    • 箭头函数不能使用 new 关键字调用。

七、函数的应用场景

  1. 代码复用

    • 将重复的逻辑封装成函数,减少代码冗余。
  2. 模块化开发

    • 通过函数将代码划分为独立的模块,提高可维护性。
  3. 回调函数

    • 将函数作为参数传递给其他函数,用于异步编程或事件处理。
  4. 高阶函数与函数式编程

    • 使用高阶函数实现抽象和组合,提升代码的灵活性和可读性。