阿里云主机折上折
  • 微信号
Current Site:Index > Function definition specification

Function definition specification

Author:Chuan Chen 阅读数:60790人阅读 分类: JavaScript

Function Naming Conventions

Function names should clearly express their purpose, using camelCase. Avoid single letters or vague terms, and prefer names that start with verbs. For example:

// Good naming
function calculateTotalPrice() {}
function getUserInfo() {}

// Poor naming
function calc() {} // Too brief
function data() {} // Unclear noun
function process() {} // Too generic verb

For functions that return boolean values, use prefixes like is, has, or can:

function isValidUser() {}
function hasPermission() {}
function canEditContent() {}

Parameter Design Principles

Limit the number of function parameters to 3 or fewer. For more than 3, consider using an object parameter:

// Not recommended
function createUser(name, age, gender, address, phone) {}

// Recommended
function createUser({ name, age, gender, address, phone }) {}

Set default values for parameters to avoid existence checks inside the function:

// Not recommended
function connect(host, port) {
  host = host || 'localhost';
  port = port || 8080;
}

// Recommended
function connect(host = 'localhost', port = 8080) {}

Function Length Control

A single function should ideally not exceed 20 lines (excluding blank lines and comments). Long functions should be split into smaller ones:

// Not recommended
function processOrder(order) {
  // Validation logic...15 lines
  // Calculation logic...20 lines
  // Database operations...15 lines
  // Notification logic...10 lines
}

// Recommended
function processOrder(order) {
  validateOrder(order);
  const total = calculateTotal(order);
  saveOrder(order, total);
  notifyUser(order);
}

Single Responsibility Principle

Each function should do only one thing and avoid side effects:

// Not recommended: Modifies data and sends notifications
function updateUserProfile(user) {
  user.updatedAt = new Date();
  database.save(user);
  emailService.sendUpdateNotification(user.email);
}

// Recommended: Split responsibilities
function updateUserProfile(user) {
  markAsUpdated(user);
  persistUser(user);
}

function markAsUpdated(user) {
  user.updatedAt = new Date();
}

function persistUser(user) {
  database.save(user);
  notifyProfileUpdate(user);
}

Return Value Consistency

Functions should maintain consistent return types, avoiding cases where they sometimes return an object and sometimes return null:

// Not recommended
function findUser(id) {
  const user = database.query(id);
  return user || null; // Sometimes User object, sometimes null
}

// Recommended: Always return a User object or throw an exception
function findUser(id) {
  const user = database.query(id);
  if (!user) throw new Error('User not found');
  return user;
}

For operations that may fail, consider returning an object with a status:

function divide(a, b) {
  if (b === 0) {
    return { success: false, error: 'Cannot divide by zero' };
  }
  return { success: true, value: a / b };
}

Error Handling Standards

Error handling should be explicit, avoiding silent failures:

// Not recommended
function parseJSON(json) {
  try {
    return JSON.parse(json);
  } catch {
    return null;
  }
}

// Recommended: Explicitly throw errors
function parseJSON(json) {
  try {
    return JSON.parse(json);
  } catch (error) {
    throw new Error(`Invalid JSON: ${error.message}`);
  }
}

For expected errors (e.g., validation failures), return error objects instead of throwing exceptions:

function validateEmail(email) {
  const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  if (!regex.test(email)) {
    return { valid: false, reason: 'Invalid email format' };
  }
  return { valid: true };
}

Pure Functions Preferred

Write pure functions whenever possible, where the same input always produces the same output:

// Impure: Depends on external state
let discount = 0.1;
function applyDiscount(price) {
  return price * (1 - discount);
}

// Pure function
function applyDiscount(price, discount) {
  return price * (1 - discount);
}

Higher-Order Function Usage

Use higher-order functions to improve code reusability:

// Create function factories
function createMultiplier(factor) {
  return function(number) {
    return number * factor;
  };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

// Use function composition
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
);

Arrow Function Use Cases

Arrow functions are suitable for short callbacks, while regular functions are better for scenarios requiring this binding:

// Suitable for arrow functions
const numbers = [1, 2, 3];
const doubled = numbers.map(n => n * 2);

// Scenarios requiring `this` binding
const calculator = {
  value: 1,
  add: function(amount) {
    this.value += amount;
    return this;
  }
};

Commenting Standards

Add JSDoc comments for complex functions:

/**
 * Calculate the distance between two points
 * @param {Object} point1 - First point
 * @param {number} point1.x - X coordinate
 * @param {number} point1.y - Y coordinate
 * @param {Object} point2 - Second point
 * @param {number} point2.x - X coordinate
 * @param {number} point2.y - Y coordinate
 * @returns {number} Straight-line distance between the points
 */
function calculateDistance(point1, point2) {
  const dx = point1.x - point2.x;
  const dy = point1.y - point2.y;
  return Math.sqrt(dx * dx + dy * dy);
}

Performance Considerations

Avoid creating unnecessary functions in hot paths:

// Not recommended: Creates a new function on every render
function Component() {
  const handleClick = () => {
    console.log('Clicked');
  };
  return <button onClick={handleClick}>Click</button>;
}

// Recommended: Cache with useCallback
function Component() {
  const handleClick = useCallback(() => {
    console.log('Clicked');
  }, []);
  return <button onClick={handleClick}>Click</button>;
}

For frequently called simple functions, consider performance optimizations:

// Simple operations can be inlined
array.forEach(item => processItem(item));

// Complex operations should be extracted as separate functions
function processItem(item) {
  // Complex processing logic
}
array.forEach(processItem);

Asynchronous Function Standards

Asynchronous functions should be explicitly marked with async and handle errors properly:

// Not recommended: Ignores error handling
async function fetchData() {
  const response = await fetch('/api/data');
  return response.json();
}

// Recommended: Complete error handling
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; // Or return a default value
  }
}

Use Promise.all to optimize multiple asynchronous operations:

async function fetchMultipleResources() {
  const [user, posts] = await Promise.all([
    fetch('/api/user'),
    fetch('/api/posts')
  ]);
  return {
    user: await user.json(),
    posts: await posts.json()
  };
}

Functional Programming Practices

Use functional programming concepts appropriately:

// Use currying
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

Type Safety Considerations

Define function types explicitly in TypeScript:

// Explicitly define parameter and return types
function formatName(firstName: string, lastName: string): string {
  return `${lastName}, ${firstName}`;
}

// Use interfaces for complex parameters
interface User {
  id: number;
  name: string;
}

function getUserInfo(user: User): string {
  return `ID: ${user.id}, Name: ${user.name}`;
}

Test-Friendly Design

Write functions that are easy to test:

// Not recommended: Directly depends on external services
async function getWeather() {
  const response = await fetch('https://api.weather.com');
  return response.json();
}

// Recommended: Inject dependencies
async function getWeather(fetchService = fetch) {
  const response = await fetchService('https://api.weather.com');
  return response.json();
}

// Can inject mocks during testing
test('getWeather', async () => {
  const mockFetch = jest.fn().mockResolvedValue({ json: () => ({ temp: 25 }) });
  const weather = await getWeather(mockFetch);
  expect(weather.temp).toBe(25);
});

Code Organization Suggestions

Group related functions together:

// userUtils.js
export function validateUser(user) {
  // Validation logic
}

export function formatUserName(user) {
  // Formatting logic
}

export function saveUser(user) {
  // Saving logic
}

// Import as needed
import { validateUser, formatUserName } from './userUtils';

Parameter Validation Best Practices

Validate parameters at the function entry point:

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');
  }
  
  // Normal logic
}

Recursive Function Notes

Recursive functions must have a termination condition:

// Calculate factorial
function factorial(n) {
  if (n < 0) throw new Error('Negative numbers not allowed');
  if (n <= 1) return 1; // Termination condition
  return n * factorial(n - 1);
}

// Tail recursion optimization (JavaScript engines may not optimize this)
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);
}

Function Overloading Patterns

Simulate function overloading in JavaScript:

function createElement(tag, options) {
  if (typeof tag === 'string') {
    // Handle string tag names
    const element = document.createElement(tag);
    if (options) applyOptions(element, options);
    return element;
  } else if (tag instanceof Function) {
    // Handle component functions
    return tag(options);
  }
  throw new Error('Invalid tag parameter');
}

function applyOptions(element, options) {
  // Apply various options
}

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

上一篇:变量声明规范

下一篇:注释规范

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.