Appearance
JS 函数
函数的概念
函数是一段可重用的代码块,用于执行特定的任务。函数可以接受输入参数,执行操作,并返回结果。在 JavaScript 中,函数是一等公民,这意味着它们可以像其他值一样被传递、赋值给变量、作为参数传递给其他函数,以及作为函数的返回值。
函数的分类
1. 命名函数
命名函数是有名称的函数,可以通过名称调用:
javascript
function add(a, b) {
return a + b;
}
console.log(add(5, 10)); // 输出: 152. 匿名函数
匿名函数是没有名称的函数,通常作为值赋给变量或作为参数传递给其他函数:
javascript
const add = function(a, b) {
return a + b;
};
console.log(add(5, 10)); // 输出: 15
// 作为参数传递
setTimeout(function() {
console.log('Hello, World!');
}, 1000);3. 箭头函数
箭头函数是 ES6 引入的一种更简洁的函数语法:
javascript
const add = (a, b) => a + b;
console.log(add(5, 10)); // 输出: 15
// 单个参数
const square = x => x * x;
console.log(square(5)); // 输出: 25
// 无参数
const greet = () => 'Hello, World!';
console.log(greet()); // 输出: Hello, World!
// 多行函数体
const multiply = (a, b) => {
const result = a * b;
return result;
};
console.log(multiply(5, 10)); // 输出: 504. 立即执行函数表达式 (IIFE)
IIFE 是一种立即执行的函数表达式:
javascript
(function() {
console.log('This function executes immediately');
})();
// 带参数的 IIFE
(function(name) {
console.log(`Hello, ${name}!`);
})('John');
// 箭头函数形式
(() => {
console.log('Arrow function IIFE');
})();5. 生成器函数
生成器函数是 ES6 引入的一种特殊函数,可以暂停和恢复执行:
javascript
function* generateNumbers() {
yield 1;
yield 2;
yield 3;
}
const generator = generateNumbers();
console.log(generator.next().value); // 输出: 1
console.log(generator.next().value); // 输出: 2
console.log(generator.next().value); // 输出: 3
console.log(generator.next().value); // 输出: undefined6. 异步函数
异步函数是 ES2017 引入的一种函数,可以使用 async 和 await 关键字处理异步操作:
javascript
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
} catch (error) {
console.error('Error fetching data:', error);
throw error;
}
}
fetchData()
.then(data => console.log(data))
.catch(error => console.error(error));函数的特性
1. 函数作用域
在函数内部声明的变量具有函数作用域,只能在函数内部访问:
javascript
function myFunction() {
const localVar = 'Local';
console.log(localVar); // 输出: Local
}
myFunction();
// console.log(localVar); // 错误:无法访问局部变量2. 闭包
闭包是指函数能够访问其词法作用域之外的变量:
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()); // 输出: 33. 函数提升
函数声明会被提升到作用域的顶部,因此可以在声明之前调用:
javascript
console.log(add(5, 10)); // 输出: 15(函数声明被提升)
function add(a, b) {
return a + b;
}
// 函数表达式不会被提升
// console.log(subtract(10, 5)); // 错误:subtract 未定义
const subtract = function(a, b) {
return a - b;
};4. this 关键字
在函数内部,this 关键字指向调用该函数的对象:
javascript
const person = {
name: 'John',
greet: function() {
return `Hello, ${this.name}!`;
}
};
console.log(person.greet()); // 输出: Hello, John!
// 箭头函数中的 this
const person2 = {
name: 'John',
greet: () => {
return `Hello, ${this.name}!`; // 箭头函数中的 this 指向外部作用域
}
};
console.log(person2.greet()); // 输出: Hello, undefined!函数的应用
1. 模块化
使用函数可以将代码组织成模块,提高代码的可维护性:
javascript
// 数学模块
const math = {
add: function(a, b) {
return a + b;
},
subtract: function(a, b) {
return a - b;
},
multiply: function(a, b) {
return a * b;
},
divide: function(a, b) {
if (b === 0) {
throw new Error('Division by zero');
}
return a / b;
}
};
console.log(math.add(5, 10)); // 输出: 15
console.log(math.subtract(10, 5)); // 输出: 52. 回调函数
函数可以作为参数传递给其他函数,用于处理异步操作或事件:
javascript
// 异步操作
function fetchData(url, callback) {
setTimeout(() => {
const data = { id: 1, name: 'John' };
callback(null, data);
}, 1000);
}
fetchData('https://api.example.com/data', function(error, data) {
if (error) {
console.error('Error:', error);
} else {
console.log('Data:', data);
}
});
// 事件处理
const button = document.getElementById('myButton');
button.addEventListener('click', function() {
console.log('Button clicked!');
});3. 高阶函数
高阶函数是接受函数作为参数或返回函数的函数:
javascript
// 接受函数作为参数
function map(array, callback) {
const result = [];
for (let i = 0; i < array.length; i++) {
result.push(callback(array[i], i, array));
}
return result;
}
const numbers = [1, 2, 3, 4, 5];
const doubled = map(numbers, function(num) {
return num * 2;
});
console.log(doubled); // 输出: [2, 4, 6, 8, 10]
// 返回函数
function createMultiplier(multiplier) {
return function(num) {
return num * multiplier;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 输出: 10
console.log(triple(5)); // 输出: 154. 递归
递归是指函数调用自身的过程:
javascript
// 计算阶乘
function factorial(n) {
if (n === 0) {
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函数的最佳实践
1. 函数命名
- 函数名应该具有描述性,清晰地表达函数的功能
- 使用驼峰命名法(camelCase)
- 动词开头表示动作
javascript
// 好的函数名
function calculateSum(a, b) {
return a + b;
}
function getUserData(id) {
// 获取用户数据
}
// 不好的函数名
function sum(a, b) {
return a + b;
}
function data(id) {
// 获取用户数据
}2. 函数长度
- 函数应该保持简短,通常不超过 20-30 行
- 一个函数应该只做一件事
- 对于复杂的功能,将其分解为多个小函数
3. 参数数量
- 函数参数数量应该合理,通常不超过 3-4 个
- 对于多个参数,考虑使用对象作为参数
javascript
// 好的做法
function createUser({ name, email, age }) {
// 创建用户
}
createUser({ name: 'John', email: 'john@example.com', age: 30 });
// 不好的做法
function createUser(name, email, age, address, phone) {
// 创建用户
}4. 错误处理
- 函数应该处理可能的错误
- 使用 try/catch 语句捕获错误
- 返回适当的错误信息
javascript
function divide(a, b) {
if (b === 0) {
throw new Error('Division by zero');
}
return a / b;
}
try {
console.log(divide(10, 0));
} catch (error) {
console.error(error.message);
}5. 文档
- 为函数添加注释,说明函数的用途、参数和返回值
- 使用 JSDoc 格式
javascript
/**
* 计算两个数的和
* @param {number} a - 第一个数
* @param {number} b - 第二个数
* @returns {number} 两个数的和
*/
function add(a, b) {
return a + b;
}小结
函数是 JavaScript 中的核心概念之一,它允许我们将代码组织成可重用的块。JavaScript 提供了多种类型的函数,包括命名函数、匿名函数、箭头函数、生成器函数和异步函数。理解函数的特性和应用,是学习 JavaScript 的基础。在实际开发中,应该遵循最佳实践,编写清晰、简洁、可维护的函数。