JavaScript 函数基础
概述
函数是JavaScript中的基本构建块,用于封装可重用的代码逻辑。JavaScript中函数是一等公民,可以作为值传递、存储和操作。
函数声明
基本语法
function functionName(parameters) {
// 函数体
return value; // 可选
}
函数声明示例
// 基本函数声明
function greet(name) {
return `Hello, ${name}!`;
}
// 多参数函数
function add(a, b) {
return a + b;
}
// 无返回值函数
function logMessage(message) {
console.log(message);
}
// 默认参数(ES6+)
function greetWithDefault(name = "World") {
return `Hello, ${name}!`;
}
函数提升
// 函数声明会被提升,可以在声明前调用
console.log(sum(1, 2)); // 3 - 正常工作
function sum(a, b) {
return a + b;
}
函数表达式
基本语法
const functionName = function(parameters) {
// 函数体
return value;
};
函数表达式示例
// 匿名函数表达式
const multiply = function(a, b) {
return a * b;
};
// 具名函数表达式(便于调试)
const divide = function divide(a, b) {
if (b === 0) {
throw new Error('Division by zero');
}
return a / b;
};
// 立即执行函数表达式(IIFE)
const result = (function(x, y) {
return x + y;
})(5, 3);
函数表达式的提升
// 错误:函数表达式不会提升
console.log(subtract(5, 3)); // TypeError: subtract is not a function
const subtract = function(a, b) {
return a - b;
};
箭头函数(ES6+)
基本语法
const functionName = (parameters) => {
// 函数体
return value;
};
// 简写形式
const functionName = parameter => expression;
const functionName = (a, b) => a + b;
箭头函数示例
// 基本箭头函数
const square = x => x * x;
// 多参数箭头函数
const add = (a, b) => a + b;
// 无参数箭头函数
const getCurrentTime = () => new Date().getTime();
// 返回对象的箭头函数(需要括号)
const createUser = (name, age) => ({ name, age });
// 多行箭头函数
const processData = data => {
const processed = data.map(item => item * 2);
return processed.filter(item => item > 10);
};
箭头函数的限制
// 1. 没有自己的this
const obj = {
name: 'Object',
regularMethod: function() {
console.log(this.name); // 'Object'
},
arrowMethod: () => {
console.log(this.name); // undefined(或全局对象的name)
}
};
// 2. 不能作为构造函数
const Person = (name) => {
this.name = name; // 错误用法
};
// new Person('John'); // TypeError
// 3. 没有arguments对象
function regularFunc() {
console.log(arguments); // Arguments对象
}
const arrowFunc = () => {
console.log(arguments); // ReferenceError
};
// 使用剩余参数替代
const arrowWithRest = (...args) => {
console.log(args); // 数组
};
参数处理
默认参数
// ES6之前的方法
function greetOld(name) {
name = name || 'World';
return `Hello, ${name}!`;
}
// ES6默认参数
function greet(name = 'World') {
return `Hello, ${name}!`;
}
// 复杂默认值
function createUser(name, age = 18, active = true) {
return { name, age, active };
}
// 使用函数作为默认值
function log(message, timestamp = Date.now()) {
console.log(`[${timestamp}] ${message}`);
}
剩余参数
// 收集多余参数
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3, 4, 5)); // 15
// 与普通参数结合
function introduce(name, ...hobbies) {
console.log(`我是${name}`);
if (hobbies.length > 0) {
console.log(`我的爱好是:${hobbies.join('、')}`);
}
}
introduce('张三', '阅读', '游泳', '编程');
参数解构
// 对象参数解构
function createUser({ name, age = 18, email }) {
return { name, age, email };
}
createUser({ name: '张三', email: 'zhang@example.com' });
// 数组参数解构
function getCoordinates([x, y, z = 0]) {
return { x, y, z };
}
getCoordinates([1, 2]); // { x: 1, y: 2, z: 0 }
返回值
基本返回值
// 明确返回值
function add(a, b) {
return a + b;
}
// 条件返回
function getAbsoluteValue(num) {
if (num >= 0) {
return num;
} else {
return -num;
}
}
// 早期返回
function validateUser(user) {
if (!user) return { valid: false, error: '用户不存在' };
if (!user.name) return { valid: false, error: '姓名为空' };
if (!user.email) return { valid: false, error: '邮箱为空' };
return { valid: true };
}
隐式返回
// 函数没有return语句,隐式返回undefined
function logMessage(msg) {
console.log(msg);
// 隐式返回undefined
}
// 箭头函数的隐式返回
const double = x => x * 2; // 隐式返回x * 2
// 返回对象需要括号
const createPoint = (x, y) => ({ x, y });
作用域和闭包
函数作用域
function outerFunction(x) {
const outerVariable = x;
function innerFunction(y) {
const innerVariable = y;
console.log(outerVariable); // 可以访问外部变量
console.log(innerVariable);
}
innerFunction(20);
// console.log(innerVariable); // 错误:不能访问内部变量
}
outerFunction(10);
闭包
// 基本闭包
function createCounter() {
let count = 0;
return function() {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
// 闭包的实际应用:模块模式
function createCalculator() {
let result = 0;
return {
add: (x) => { result += x; return result; },
subtract: (x) => { result -= x; return result; },
multiply: (x) => { result *= x; return result; },
divide: (x) => { result /= x; return result; },
clear: () => { result = 0; return result; },
getResult: () => result
};
}
const calc = createCalculator();
calc.add(10).multiply(2).subtract(5); // 链式调用
console.log(calc.getResult()); // 15
高阶函数
函数作为参数
// 基本示例
function processArray(arr, callback) {
const result = [];
for (const item of arr) {
result.push(callback(item));
}
return result;
}
const numbers = [1, 2, 3, 4, 5];
const doubled = processArray(numbers, x => x * 2);
// 内置高阶函数
const evenNumbers = numbers.filter(x => x % 2 === 0);
const squared = numbers.map(x => x * x);
const sum = numbers.reduce((acc, x) => acc + x, 0);
函数作为返回值
// 函数工厂
function createValidator(min, max) {
return function(value) {
return value >= min && value <= max;
};
}
const ageValidator = createValidator(18, 65);
console.log(ageValidator(25)); // true
console.log(ageValidator(15)); // false
// 偏函数应用
function multiply(a, b) {
return a * b;
}
function partial(fn, ...args1) {
return function(...args2) {
return fn(...args1, ...args2);
};
}
const double = partial(multiply, 2);
console.log(double(5)); // 10
递归函数
基本递归
// 计算阶乘
function factorial(n) {
if (n <= 1) {
return 1; // 基础情况
}
return n * factorial(n - 1); // 递归调用
}
// 斐波那契数列
function fibonacci(n) {
if (n <= 1) {
return n;
}
return fibonacci(n - 1) + fibonacci(n - 2);
}
// 优化的斐波那契(避免重复计算)
function fibonacciOptimized(n, memo = {}) {
if (n in memo) {
return memo[n];
}
if (n <= 1) {
return n;
}
memo[n] = fibonacciOptimized(n - 1, memo) + fibonacciOptimized(n - 2, memo);
return memo[n];
}
递归遍历
// 遍历嵌套对象
function traverse(obj, callback) {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
callback(key, obj[key]);
if (typeof obj[key] === 'object' && obj[key] !== null) {
traverse(obj[key], callback);
}
}
}
}
const data = {
name: 'root',
children: {
child1: { value: 1 },
child2: { value: 2, nested: { deep: 'value' } }
}
};
traverse(data, (key, value) => {
console.log(`${key}: ${value}`);
});
最佳实践
1. 函数命名
// 使用动词开头的描述性名称
function calculateTotalPrice(items) { /* ... */ }
function validateEmailAddress(email) { /* ... */ }
function renderUserProfile(user) { /* ... */ }
// 布尔返回值函数使用is/has/can开头
function isValidUser(user) { /* ... */ }
function hasPermission(user, permission) { /* ... */ }
function canEdit(user, document) { /* ... */ }
2. 函数长度和职责
// 好:单一职责
function calculateTax(amount, rate) {
return amount * rate;
}
function formatCurrency(amount) {
return `$${amount.toFixed(2)}`;
}
function calculateTotalWithTax(amount, taxRate) {
const tax = calculateTax(amount, taxRate);
const total = amount + tax;
return formatCurrency(total);
}
// 避免:过长的函数
function processOrder(order) {
// 100+ 行代码处理订单的各个方面
// 应该拆分成多个小函数
}
3. 纯函数
// 纯函数:相同输入总是产生相同输出,无副作用
function add(a, b) {
return a + b;
}
function multiply(arr, factor) {
return arr.map(x => x * factor);
}
// 避免副作用
// 不好:修改外部状态
let globalCount = 0;
function incrementCount() {
globalCount++; // 副作用
}
// 好:返回新值
function increment(count) {
return count + 1;
}
4. 错误处理
// 输入验证
function divide(a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
throw new TypeError('参数必须是数字');
}
if (b === 0) {
throw new Error('除数不能为零');
}
return a / b;
}
// 优雅的错误处理
function safeJsonParse(jsonString) {
try {
return { success: true, data: JSON.parse(jsonString) };
} catch (error) {
return { success: false, error: error.message };
}
}