Sign In Create Account
Variables & Functions

Variables & Functions

Best practices for variable assignment, naming, and function declarations.

Variable Assignment

  • • Prefer const over let
  • • Use let only when a variable will be reassigned
  • • Never use var
  • • Declare variables at the top of their scope when possible

Variable Assignment Examples

// ✅ Preferred - use const by default
const userName = 'Sebastian';
const userAge = 28;
const userPreferences = {
  theme: 'dark',
  language: 'en',
  notifications: true
};

// ✅ Use let when reassignment is needed
let currentStep = 1;
let isLoading = false;

function processSteps() {
  for (let i = 0; i < steps.length; i++) {
    currentStep = i + 1; // Reassignment needed
    processStep(steps[i]);
  }
  
  isLoading = true; // State change
}

// ✅ Modifying object properties is allowed with const
const user = { name: 'Alice', age: 30 };
user.age = 31; // This is fine - we're not reassigning 'user'
user.email = '[email protected]'; // Adding properties is also fine

// ❌ Avoid var - has function scope and hoisting issues
var count = 0; // Don't do this
if (true) {
  var message = 'Hello'; // This is hoisted and can cause confusion
}

// ❌ Don't use let when const would work
let API_URL = 'https://api.example.com'; // Should be const
let processedData = transformData(rawData); // Should be const if not reassigned

Why Prefer const?

  • Immutability Signal: Clearly indicates the variable won't be reassigned
  • Prevents Bugs: Catches accidental reassignments at compile time
  • Better Optimization: Engines can better optimize const variables
  • Easier Reasoning: Developers can trust the variable won't change

Variable Names

  • • Avoid abbreviations in most cases
  • • Single-letter variables are acceptable in short, clear contexts like array methods
  • • Use descriptive names that communicate intent
  • • Boolean variables should be questions (is, has, can, should)

Variable Naming Examples

// ✅ Descriptive variable names
const userEmailAddress = '[email protected]';
const shoppingCartItems = [];
const hasActiveSubscription = true;
const isEmailVerified = false;
const canEditProfile = user.role === 'admin';
const shouldShowWelcomeMessage = isFirstVisit && !hasSeenWelcome;

// ✅ Acceptable single-letter variables in clear contexts
const numbers = [1, 2, 3, 4, 5];
const doubledNumbers = numbers.map(n => n * 2);
const filteredUsers = users.filter(u => u.isActive);

// ✅ Good function parameter names
function calculateShippingCost(orderTotal, shippingDistance, isPriorityDelivery) {
  // Implementation
}

// ❌ Poor variable names
const e = '[email protected]'; // What is 'e'?
const addr = getUserAddress(); // Abbreviation unclear
const flag = true; // What does this flag represent?
const data = fetchUserInfo(); // Too generic
const temp = calculateTotal(); // Temporary for what?

// ❌ Boolean variables that don't ask questions
const subscription = true; // Should be 'hasSubscription'
const email = false; // Should be 'isEmailVerified' or 'hasEmail'

Comparisons

  • • Always use strict equality (===)
  • • Cast types explicitly if type comparison is uncertain
  • • Never use loose equality (==) unless absolutely necessary
  • • Use explicit checks for null/undefined when needed

Comparison Examples

// ✅ Strict equality - always preferred
const userAge = 25;
const inputAge = '25';

if (userAge === parseInt(inputAge, 10)) {
  console.log('Ages match');
}

// ✅ Explicit type checking
if (typeof value === 'string' && value.length > 0) {
  processString(value);
}

// ✅ Explicit null/undefined checks
if (user.email !== null && user.email !== undefined) {
  sendEmail(user.email);
}

// ✅ Using nullish coalescing operator
const displayName = user.fullName ?? user.username ?? 'Anonymous';

// ✅ Checking for array length
if (items.length === 0) {
  showEmptyState();
}

// ❌ Loose equality - can cause unexpected behavior
if (userAge == inputAge) { // '25' == 25 is true, but types differ
  console.log('This might not be what you expect');
}

// ❌ Truthy/falsy when you need exact values
if (items.length) { // What if length is exactly what we're checking?
  // This fails when length is 0, but 0 might be a valid value
}

// ❌ Implicit type coercion
if (userInput) { // What if userInput is '0' or false intentionally?
  processInput(userInput);
}

Common Equality Gotchas

// These all return true with == (but false with ===)
0 == false
'' == false
null == undefined
'0' == false
[] == false

// Always use === to avoid these surprises
0 === false        // false
'' === false       // false  
null === undefined // false

Functions

Function Declarations

  • • Use function declarations for named functions
  • • Use arrow functions for anonymous functions and callbacks
  • • Use method shorthand for object methods
  • • Prefer named functions over anonymous functions for debugging

Function Declaration Examples

// ✅ Function declarations for named functions
function calculateTax(amount, rate) {
  return amount * rate;
}

function processUser(user) {
  validateUser(user);
  saveUser(user);
  sendWelcomeEmail(user);
}

// ✅ Arrow functions for short, anonymous functions
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);

// ✅ Arrow functions for callbacks
button.addEventListener('click', () => {
  toggleMenu();
});

// ✅ Object method shorthand
const userService = {
  async createUser(userData) {
    const user = await this.validateUserData(userData);
    return await this.saveToDatabase(user);
  },
  
  validateUserData(data) {
    // Validation logic
    return data;
  }
};

// ✅ Named arrow functions for better debugging
const calculateDiscount = (price, percentage) => {
  return price * (percentage / 100);
};

// ❌ Avoid anonymous functions when debugging is important
users.forEach(function(user) { // Hard to identify in stack traces
  processUser(user);
});

// ✅ Better - named function
users.forEach(function processUserCallback(user) {
  processUser(user);
});

Function Parameters

  • • Use default parameters instead of checking for undefined
  • • Use destructuring for object parameters
  • • Limit the number of parameters (prefer objects for many parameters)
  • • Use rest parameters instead of the arguments object

Function Parameter Examples

// ✅ Default parameters
function greetUser(name = 'Guest', greeting = 'Hello') {
  return `${greeting}, ${name}!`;
}

// ✅ Object destructuring for parameters
function createUser({ name, email, age = 18, isAdmin = false }) {
  return {
    name,
    email,
    age,
    isAdmin,
    createdAt: new Date()
  };
}

// ✅ Usage with object parameters
const newUser = createUser({
  name: 'Alice',
  email: '[email protected]',
  age: 25
});

// ✅ Rest parameters
function sum(...numbers) {
  return numbers.reduce((total, num) => total + num, 0);
}

// ✅ Combining destructuring with rest parameters
function processApiResponse({ data, status, ...metadata }) {
  console.log('Status:', status);
  console.log('Data:', data);
  console.log('Metadata:', metadata);
}

// ❌ Too many individual parameters
function createUser(name, email, age, isAdmin, createdDate, lastLogin, preferences, settings) {
  // Hard to remember parameter order and meaning
}

// ❌ Using arguments object
function sum() {
  let total = 0;
  for (let i = 0; i < arguments.length; i++) {
    total += arguments[i]; // arguments is not a real array
  }
  return total;
}