知识篇 -- JS函数详解

Ray Shine 2024/2/8 JavaScript基础知识

函数是JavaScript中最核心的概念之一,它是组织代码、实现模块化和代码复用的基本单位。通过函数,我们可以将一系列操作封装起来,并在需要时多次调用,避免重复编写相同的代码。理解函数的定义、调用、参数、返回值以及不同类型的函数,是编写高效、可维护JavaScript代码的关键。

# 一、函数的定义与调用 基础

JavaScript提供了多种定义函数的方式:

# 1. 函数声明 (Function Declaration) 可提升

function greet(name) {
    return "Hello, " + name + "!";
}

特点

  • 函数提升 (Hoisting):函数声明会被提升到其所在作用域的顶部,这意味着你可以在函数声明之前调用它。
  • 命名函数:函数有名称,便于调试和递归调用。

# 2. 函数表达式 (Function Expression) 灵活

const sayHello = function(name) {
    return "Hello, " + name + "!";
};

特点

  • 不会提升:函数表达式不会被提升,必须在定义之后才能调用。
  • 匿名函数或命名函数:可以是匿名函数(如上例),也可以是命名函数表达式(const sayHello = function funcName(name) {...}),命名函数表达式的名称只在函数内部可见。

# 3. 箭头函数 (Arrow Function) (ES6新增) 简洁

const add = (a, b) => a + b;
const sayHi = name => console.log(`Hi, ${name}!`); // 单个参数可省略括号
const getMessage = () => "This is a message."; // 无参数需保留空括号

特点

  • 语法简洁:特别适用于简单的函数。
  • 没有自己的 thisthis 关键字的值由外层作用域决定(词法作用域)。
  • 不能作为构造函数:不能使用 new 关键字调用。
  • 没有 arguments 对象:但可以使用剩余参数 ...args
  • 不会提升:与函数表达式类似。

# 2. 函数的调用

定义函数后,通过函数名后跟括号 () 来调用它。

console.log(greet("Alice")); // Hello, Alice!
console.log(sayHello("Bob")); // Hello, Bob!
console.log(add(5, 3)); // 8
sayHi("Charlie"); // Hi, Charlie!

# 二、参数与返回值 核心

# 1. 参数 (Parameters)

函数可以接受零个或多个参数,这些参数是函数内部使用的局部变量。

  • 形参 (Parameters):函数定义时声明的变量。
  • 实参 (Arguments):函数调用时传递给函数的值。
  • 默认参数 (Default Parameters) (ES6新增):允许为函数参数设置默认值。
    function multiply(a, b = 2) {
        return a * b;
    }
    console.log(multiply(5));    // 10 (b使用默认值2)
    console.log(multiply(5, 3)); // 15
    
  • 剩余参数 (Rest Parameters) (ES6新增):允许将不定数量的参数表示为一个数组。
    function sumAll(...numbers) {
        return numbers.reduce((total, num) => total + num, 0);
    }
    console.log(sumAll(1, 2, 3));       // 6
    console.log(sumAll(10, 20, 30, 40)); // 100
    
  • arguments 对象:在ES5及之前,函数内部有一个类数组对象 arguments,包含了所有传递给函数的实参。但在箭头函数中没有 arguments 对象。
    function oldSum() {
        let total = 0;
        for (let i = 0; i < arguments.length; i++) {
            total += arguments[i];
        }
        return total;
    }
    console.log(oldSum(1, 2, 3)); // 6
    

# 2. 返回值 (Return Value)

函数可以通过 return 语句返回一个值。

  • 如果没有 return 语句,或者 return 后面没有值,函数会隐式返回 undefined
  • return 语句会立即终止函数的执行。
  • 示例
    function calculateArea(width, height) {
        if (width <= 0 || height <= 0) {
            return "无效的尺寸"; // 提前返回
        }
        return width * height;
    }
    console.log(calculateArea(10, 5)); // 50
    console.log(calculateArea(-2, 5)); // 无效的尺寸
    

# 三、函数作用域与闭包 (Scope and Closures) 进阶

# 1. 作用域 (Scope)

作用域决定了变量和函数在代码中的可访问性。

  • 全局作用域:在函数外部声明的变量,在程序的任何地方都可以访问。
  • 函数作用域:在函数内部声明的 var 变量,只能在该函数内部访问。
  • 块级作用域 (ES6新增):在 if 语句、for 循环或任何 {} 块中用 letconst 声明的变量,只能在该块内部访问。

# 2. 闭包 (Closures)

闭包是指函数能够记住并访问其词法作用域(即函数定义时的作用域),即使该函数在其词法作用域之外执行。

  • 形成条件:当一个内部函数引用了其外部函数作用域中的变量,并且这个内部函数被返回或传递到外部时,就形成了闭包。
  • 作用
    • 数据私有化:创建私有变量,保护数据不被外部直接访问。
    • 状态持久化:使函数能够记住其创建时的环境,保持状态。
  • 示例
    function createCounter() {
        let count = 0; // 外部函数作用域中的变量
        return function() { // 内部函数
            count++;
            console.log(count);
        };
    }
    
    const counter1 = createCounter();
    counter1(); // 1
    counter1(); // 2
    
    const counter2 = createCounter();
    counter2(); // 1 (counter1和counter2拥有独立的count变量)
    
  • 注意:过度使用闭包可能导致内存泄漏,因为闭包会阻止其引用的外部变量被垃圾回收。

# 四、this 关键字:指向何方? 难点

this 关键字是JavaScript中最复杂但又最重要的概念之一,它的值取决于函数被调用的方式。

  • 全局上下文:在全局作用域中,this 指向全局对象(浏览器中是 window,Node.js中是 global)。
  • 函数调用:普通函数调用时,this 默认指向全局对象(严格模式下为 undefined)。
  • 方法调用:作为对象的方法调用时,this 指向该对象。
  • 构造函数调用:使用 new 关键字调用时,this 指向新创建的实例对象。
  • 事件处理函数:通常指向触发事件的元素。
  • 箭头函数:箭头函数没有自己的 this,它会捕获其外层(词法)作用域的 this 值。
  • call(), apply(), bind():可以显式地改变 this 的指向。

示例

const person = {
    name: "Alice",
    greet: function() {
        console.log(`Hello, my name is ${this.name}`);
    },
    farewell: () => {
        console.log(`Goodbye from ${this.name}`); // 箭头函数this指向全局对象
    }
};

person.greet(); // Hello, my name is Alice (this指向person)
person.farewell(); // Goodbye from undefined (浏览器中,this.name会是window.name,通常为空)

const anotherGreet = person.greet;
anotherGreet(); // Hello, my name is undefined (普通函数调用,this指向全局对象)

理解函数是JavaScript编程的基石。通过掌握函数的定义、参数、返回值、作用域和 this 关键字,你将能够编写出结构清晰、功能强大且易于维护的JavaScript代码。

最后更新时间: 2025/11/20 22:59:30
ON THIS PAGE