函数定义规范
函数命名规范
函数命名应当清晰表达其功能,采用驼峰式命名法。避免使用单个字母或模糊词汇,优先选择动词开头的名称。例如:
// 好的命名
function calculateTotalPrice() {}
function getUserInfo() {}
// 差的命名
function calc() {} // 过于简略
function data() {} // 名词不明确
function process() {} // 动词太泛泛
对于布尔返回值的函数,建议使用is
、has
、can
等前缀:
function isValidUser() {}
function hasPermission() {}
function canEditContent() {}
参数设计原则
函数参数数量建议控制在3个以内。超过3个时考虑使用对象参数:
// 不推荐
function createUser(name, age, gender, address, phone) {}
// 推荐
function createUser({ name, age, gender, address, phone }) {}
参数应设置默认值,避免函数内部做参数存在性判断:
// 不推荐
function connect(host, port) {
host = host || 'localhost';
port = port || 8080;
}
// 推荐
function connect(host = 'localhost', port = 8080) {}
函数长度控制
单个函数建议不超过20行(不包括空行和注释)。过长的函数应当拆分为多个小函数:
// 不推荐
function processOrder(order) {
// 验证逻辑...15行
// 计算逻辑...20行
// 数据库操作...15行
// 通知逻辑...10行
}
// 推荐
function processOrder(order) {
validateOrder(order);
const total = calculateTotal(order);
saveOrder(order, total);
notifyUser(order);
}
单一职责原则
每个函数应当只做一件事,避免副作用:
// 不推荐:同时修改数据和发送通知
function updateUserProfile(user) {
user.updatedAt = new Date();
database.save(user);
emailService.sendUpdateNotification(user.email);
}
// 推荐:拆分职责
function updateUserProfile(user) {
markAsUpdated(user);
persistUser(user);
}
function markAsUpdated(user) {
user.updatedAt = new Date();
}
function persistUser(user) {
database.save(user);
notifyProfileUpdate(user);
}
返回值一致性
函数应当保持返回值类型一致,避免有时返回对象有时返回null:
// 不推荐
function findUser(id) {
const user = database.query(id);
return user || null; // 有时User对象,有时null
}
// 推荐:始终返回User对象或抛出异常
function findUser(id) {
const user = database.query(id);
if (!user) throw new Error('User not found');
return user;
}
对于可能失败的操作,考虑返回包含状态的对象:
function divide(a, b) {
if (b === 0) {
return { success: false, error: 'Cannot divide by zero' };
}
return { success: true, value: a / b };
}
错误处理规范
错误处理应当明确,避免静默失败:
// 不推荐
function parseJSON(json) {
try {
return JSON.parse(json);
} catch {
return null;
}
}
// 推荐:明确抛出错误
function parseJSON(json) {
try {
return JSON.parse(json);
} catch (error) {
throw new Error(`Invalid JSON: ${error.message}`);
}
}
对于预期内的错误(如验证失败),使用返回错误对象而非抛出异常:
function validateEmail(email) {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!regex.test(email)) {
return { valid: false, reason: 'Invalid email format' };
}
return { valid: true };
}
纯函数优先
尽可能编写纯函数,相同的输入总是产生相同的输出:
// 不纯:依赖外部状态
let discount = 0.1;
function applyDiscount(price) {
return price * (1 - discount);
}
// 纯函数
function applyDiscount(price, discount) {
return price * (1 - discount);
}
高阶函数使用
合理使用高阶函数提高代码复用性:
// 创建函数工厂
function createMultiplier(factor) {
return function(number) {
return number * factor;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
// 使用函数组合
function pipe(...fns) {
return function(initialValue) {
return fns.reduce((val, fn) => fn(val), initialValue);
};
}
const processValue = pipe(
x => x * 2,
x => x + 3,
x => x / 2
);
箭头函数适用场景
箭头函数适合简短的回调,常规函数更适合需要this
绑定的场景:
// 适合箭头函数
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);
// 需要this绑定的场景
const calculator = {
value: 1,
add: function(amount) {
this.value += amount;
return this;
}
};
注释规范
为复杂函数添加JSDoc注释:
/**
* 计算两个坐标点之间的距离
* @param {Object} point1 - 第一个点
* @param {number} point1.x - x坐标
* @param {number} point1.y - y坐标
* @param {Object} point2 - 第二个点
* @param {number} point2.x - x坐标
* @param {number} point2.y - y坐标
* @returns {number} 两点间的直线距离
*/
function calculateDistance(point1, point2) {
const dx = point1.x - point2.x;
const dy = point1.y - point2.y;
return Math.sqrt(dx * dx + dy * dy);
}
性能考量
避免在热点路径上创建不必要的函数:
// 不推荐:每次渲染都创建新函数
function Component() {
const handleClick = () => {
console.log('Clicked');
};
return <button onClick={handleClick}>Click</button>;
}
// 推荐:使用useCallback缓存
function Component() {
const handleClick = useCallback(() => {
console.log('Clicked');
}, []);
return <button onClick={handleClick}>Click</button>;
}
对于频繁调用的简单函数,考虑性能优化:
// 简单操作直接内联
array.forEach(item => processItem(item));
// 复杂操作提取为独立函数
function processItem(item) {
// 复杂处理逻辑
}
array.forEach(processItem);
异步函数规范
异步函数应当明确标记async
,并正确处理错误:
// 不推荐:忽略错误处理
async function fetchData() {
const response = await fetch('/api/data');
return response.json();
}
// 推荐:完整错误处理
async function fetchData() {
try {
const response = await fetch('/api/data');
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('Failed to fetch data:', error);
throw error; // 或者返回默认值
}
}
使用Promise.all优化多个异步操作:
async function fetchMultipleResources() {
const [user, posts] = await Promise.all([
fetch('/api/user'),
fetch('/api/posts')
]);
return {
user: await user.json(),
posts: await posts.json()
};
}
函数式编程实践
合理使用函数式编程概念:
// 使用柯里化
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...moreArgs) {
return curried.apply(this, args.concat(moreArgs));
};
}
};
}
const add = curry((a, b) => a + b);
const add5 = add(5);
console.log(add5(3)); // 8
类型安全考虑
在TypeScript中明确定义函数类型:
// 明确定义参数和返回类型
function formatName(firstName: string, lastName: string): string {
return `${lastName}, ${firstName}`;
}
// 使用接口定义复杂参数
interface User {
id: number;
name: string;
}
function getUserInfo(user: User): string {
return `ID: ${user.id}, Name: ${user.name}`;
}
测试友好设计
编写易于测试的函数:
// 不推荐:直接依赖外部服务
async function getWeather() {
const response = await fetch('https://api.weather.com');
return response.json();
}
// 推荐:注入依赖
async function getWeather(fetchService = fetch) {
const response = await fetchService('https://api.weather.com');
return response.json();
}
// 测试时可以注入mock
test('getWeather', async () => {
const mockFetch = jest.fn().mockResolvedValue({ json: () => ({ temp: 25 }) });
const weather = await getWeather(mockFetch);
expect(weather.temp).toBe(25);
});
代码组织建议
相关函数应当分组组织:
// userUtils.js
export function validateUser(user) {
// 验证逻辑
}
export function formatUserName(user) {
// 格式化逻辑
}
export function saveUser(user) {
// 保存逻辑
}
// 使用时按需导入
import { validateUser, formatUserName } from './userUtils';
参数验证最佳实践
在函数入口处验证参数:
function createAccount(username, password) {
if (typeof username !== 'string' || username.length < 4) {
throw new Error('Username must be at least 4 characters');
}
if (typeof password !== 'string' || password.length < 8) {
throw new Error('Password must be at least 8 characters');
}
// 正常逻辑
}
递归函数注意事项
递归函数必须要有终止条件:
// 计算阶乘
function factorial(n) {
if (n < 0) throw new Error('Negative numbers not allowed');
if (n <= 1) return 1; // 终止条件
return n * factorial(n - 1);
}
// 尾递归优化(JavaScript引擎可能不会优化)
function factorial(n, acc = 1) {
if (n < 0) throw new Error('Negative numbers not allowed');
if (n <= 1) return acc;
return factorial(n - 1, n * acc);
}
函数重载模式
在JavaScript中模拟函数重载:
function createElement(tag, options) {
if (typeof tag === 'string') {
// 处理字符串标签名
const element = document.createElement(tag);
if (options) applyOptions(element, options);
return element;
} else if (tag instanceof Function) {
// 处理组件函数
return tag(options);
}
throw new Error('Invalid tag parameter');
}
function applyOptions(element, options) {
// 应用各种选项
}
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn