阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 函数定义规范

函数定义规范

作者:陈川 阅读数:60789人阅读 分类: JavaScript

函数命名规范

函数命名应当清晰表达其功能,采用驼峰式命名法。避免使用单个字母或模糊词汇,优先选择动词开头的名称。例如:

// 好的命名
function calculateTotalPrice() {}
function getUserInfo() {}

// 差的命名
function calc() {} // 过于简略
function data() {} // 名词不明确
function process() {} // 动词太泛泛

对于布尔返回值的函数,建议使用ishascan等前缀:

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

上一篇:变量声明规范

下一篇:注释规范

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌