درس ۱۵: توابع

یادگیری توابع JavaScript برای سازماندهی و استفاده مجدد کد

درس ۱۵ از ۲۰
پیشرفت درس

توابع چیستند؟

توابع (Functions) یکی از مهم‌ترین مفاهیم در JavaScript هستند. تابع بلوکی از کد است که برای انجام یک کار خاص طراحی شده و می‌تواند چندین بار فراخوانی شود. توابع به شما کمک می‌کنند کد خود را سازماندهی کرده و از تکرار جلوگیری کنید.

مزایای استفاده از توابع:

  • قابلیت استفاده مجدد کد (Reusability)
  • سازماندهی بهتر کد
  • تست و دیباگ آسان‌تر
  • کاهش پیچیدگی برنامه
  • تقسیم کار به بخش‌های کوچک‌تر

تعریف توابع

۱. Function Declaration

روش کلاسیک تعریف تابع:

function sayHello() {
    console.log("سلام دنیا!");
}

// فراخوانی تابع
sayHello();

۲. Function Expression

تعریف تابع به عنوان یک عبارت:

const greet = function() {
    console.log("خوش آمدید!");
};

greet();

۳. Arrow Functions

روش مدرن و کوتاه‌تر تعریف تابع:

const welcome = () => {
    console.log("به سایت ما خوش آمدید!");
};

welcome();

تمرین عملی: انواع توابع

در ادامه، انواع مختلف توابع و کاربردهای آن‌ها را مشاهده کنید:

ویرایشگر کد خط 1، ستون 1
نمایش زنده

پارامترها و آرگومان‌ها

پارامترهای ساده

function introduce(name, age, city) {
    return `سلام، من ${name} هستم، ${age} سال دارم و در ${city} زندگی می‌کنم.`;
}

console.log(introduce("علی", 25, "تهران"));

مقادیر پیش‌فرض

function greetUser(name = "کاربر", time = "روز") {
    return `${time} بخیر ${name}!`;
}

console.log(greetUser()); // "روز بخیر کاربر!"
console.log(greetUser("سارا", "شب")); // "شب بخیر سارا!"

Rest Parameters

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

console.log(sum(1, 2, 3, 4, 5)); // 15

مقادیر برگشتی

Return ساده

function calculateArea(width, height) {
    return width * height;
}

const area = calculateArea(10, 5);
console.log("مساحت:", area); // 50

Return چندگانه

function getPersonInfo(name, age) {
    return {
        fullName: name,
        years: age,
        isAdult: age >= 18,
        category: age < 13 ? "کودک" : age < 18 ? "نوجوان" : "بزرگسال"
    };
}

const person = getPersonInfo("مریم", 22);
console.log(person);

Early Return

function validateAge(age) {
    if (age < 0) {
        return "سن نمی‌تواند منفی باشد";
    }
    
    if (age > 150) {
        return "سن غیرمعقول است";
    }
    
    return "سن معتبر است";
}

محدوده متغیرها (Scope)

Global Scope

let globalVar = "من متغیر سراسری هستم";

function showGlobal() {
    console.log(globalVar); // قابل دسترسی
}

showGlobal();

Function Scope

function myFunction() {
    let localVar = "من متغیر محلی هستم";
    console.log(localVar); // قابل دسترسی
}

myFunction();
// console.log(localVar); // خطا! غیرقابل دسترسی

Block Scope

function testScope() {
    if (true) {
        let blockVar = "متغیر بلوک";
        const blockConst = "ثابت بلوک";
        console.log(blockVar); // قابل دسترسی
    }
    
    // console.log(blockVar); // خطا! غیرقابل دسترسی
}

Arrow Functions

ساختار کوتاه

// تابع معمولی
function square(x) {
    return x * x;
}

// Arrow function
const square = x => x * x;

// Arrow function با چند پارامتر
const add = (a, b) => a + b;

// Arrow function با بدنه
const processData = (data) => {
    const processed = data.map(x => x * 2);
    return processed.filter(x => x > 10);
};

تفاوت‌های مهم

⚠️ نکات مهم Arrow Functions:

  • ندارای this مخصوص به خود
  • نمی‌توان به عنوان constructor استفاده کرد
  • ندارای arguments object
  • نمی‌توان hoisted شوند

مفاهیم پیشرفته

Higher Order Functions

توابعی که توابع دیگر را به عنوان پارامتر می‌گیرند یا تابع برمی‌گردانند:

function createMultiplier(factor) {
    return function(number) {
        return number * factor;
    };
}

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

console.log(double(5)); // 10
console.log(triple(4)); // 12

Callback Functions

function processArray(array, callback) {
    const result = [];
    for (let item of array) {
        result.push(callback(item));
    }
    return result;
}

const numbers = [1, 2, 3, 4, 5];
const doubled = processArray(numbers, x => x * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

Closure

function createCounter(initialValue = 0) {
    let count = initialValue;
    
    return {
        increment: () => ++count,
        decrement: () => --count,
        getValue: () => count,
        reset: () => count = initialValue
    };
}

const counter = createCounter(10);
console.log(counter.increment()); // 11
console.log(counter.getValue()); // 11

بهترین شیوه‌ها

💡 نکات مهم:

  • نام‌گذاری: از نام‌های توصیفی استفاده کنید
  • اندازه: توابع کوچک و تک‌منظوره بنویسید
  • پارامترها: تعداد پارامترها را محدود کنید
  • مستندسازی: توابع پیچیده را مستند کنید
  • تست: توابع را به صورت جداگانه تست کنید

مثال تابع بهینه

/**
 * محاسبه قیمت نهایی با احتساب تخفیف و مالیات
 * @param {number} basePrice - قیمت پایه
 * @param {number} discountPercent - درصد تخفیف (0-100)
 * @param {number} taxPercent - درصد مالیات (0-100)
 * @returns {number} قیمت نهایی
 */
function calculateFinalPrice(basePrice, discountPercent = 0, taxPercent = 9) {
    // اعتبارسنجی ورودی
    if (basePrice < 0) throw new Error("قیمت نمی‌تواند منفی باشد");
    if (discountPercent < 0 || discountPercent > 100) {
        throw new Error("تخفیف باید بین 0 تا 100 باشد");
    }
    
    // محاسبه قیمت با تخفیف
    const discountAmount = basePrice * (discountPercent / 100);
    const priceAfterDiscount = basePrice - discountAmount;
    
    // محاسبه مالیات
    const taxAmount = priceAfterDiscount * (taxPercent / 100);
    const finalPrice = priceAfterDiscount + taxAmount;
    
    return Math.round(finalPrice * 100) / 100; // گرد کردن به 2 رقم اعشار
}

آزمون درس ۱۵

سوال ۱: کدام روش تعریف تابع hoisting ندارد؟

سوال ۲: خروجی این کد چیست؟

function test(a = 5, b = 10) {
    return a + b;
}
console.log(test(3));

سوال ۳: کدام مورد درباره Arrow Functions درست است؟