函数的基本概念
函数是一段可以重复调用的代码块,用于执行特定的任务。JavaScript 中的函数是一等公民,这意味着函数可以像其他数据类型(如数字、字符串、对象等)一样被赋值、传递和返回。
一、函数的定义
JavaScript 中定义函数的方式有多种:
-
函数声明(Function Declaration)
function greet(name) { return `Hello, ${name}!`; }- 函数声明会被提升(hoisted),即在代码执行前,函数声明会被提升到作用域的顶部,因此可以在函数声明之前调用。
-
函数表达式(Function Expression)
const greet = function(name) { return `Hello, ${name}!`; };- 函数表达式不会被提升,必须在定义后才能调用。
-
箭头函数(Arrow Function) (ES6+)
const greet = (name) => { return `Hello, ${name}!`; };- 箭头函数是函数表达式的简写形式,具有更简洁的语法。
- 箭头函数没有自己的
this,它的this继承自外层作用域。
-
立即执行函数表达式(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 引入的一种简洁的函数语法,但它与普通函数有一些重要区别:
-
没有自己的
this:- 箭头函数的
this继承自外层作用域。 - 普通函数的
this取决于调用方式。
const obj = { name: "Alice", greet: function() { setTimeout(() => { console.log(`Hello, ${this.name}!`); // 输出: Hello, Alice! }, 1000); } }; obj.greet(); - 箭头函数的
-
没有
arguments对象:- 箭头函数没有自己的
arguments对象,但可以通过剩余参数(...args)获取参数列表。
- 箭头函数没有自己的
-
不能作为构造函数:
- 箭头函数不能使用
new关键字调用。
- 箭头函数不能使用
七、函数的应用场景
-
代码复用:
- 将重复的逻辑封装成函数,减少代码冗余。
-
模块化开发:
- 通过函数将代码划分为独立的模块,提高可维护性。
-
回调函数:
- 将函数作为参数传递给其他函数,用于异步编程或事件处理。
-
高阶函数与函数式编程:
- 使用高阶函数实现抽象和组合,提升代码的灵活性和可读性。