درس ۱۹: مفاهیم پیشرفته JavaScript

یادگیری تکنیک‌ها و مفاهیم پیشرفته برای توسعه‌دهندگان حرفه‌ای

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

Closures (بسته‌ها)

Closure یکی از مفاهیم قدرتمند JavaScript است که به تابع اجازه می‌دهد به متغیرهای محدوده بیرونی خود دسترسی داشته باشد، حتی پس از اتمام اجرای تابع بیرونی.

مزایای Closures:

  • ایجاد متغیرهای خصوصی (Private Variables)
  • Factory Functions
  • Module Pattern
  • Callback Functions
  • Event Handlers
// مثال ساده Closure
function outerFunction(x) {
    // متغیر محلی
    const outerVariable = x;
    
    // تابع داخلی که به متغیر بیرونی دسترسی دارد
    function innerFunction(y) {
        return outerVariable + y;
    }
    
    return innerFunction;
}

const addFive = outerFunction(5);
console.log(addFive(3)); // 8

// مثال متغیر خصوصی
function createCounter() {
    let count = 0;
    
    return {
        increment: () => ++count,
        decrement: () => --count,
        getCount: () => count
    };
}

const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.getCount()); // 1

Promises و Async/Await

برای مدیریت عملیات ناهمزمان (Asynchronous) در JavaScript:

Promises

// ایجاد Promise
const myPromise = new Promise((resolve, reject) => {
    const success = Math.random() > 0.5;
    
    setTimeout(() => {
        if (success) {
            resolve('عملیات موفق بود!');
        } else {
            reject('خطا رخ داد!');
        }
    }, 1000);
});

// استفاده از Promise
myPromise
    .then(result => console.log(result))
    .catch(error => console.error(error))
    .finally(() => console.log('عملیات تمام شد'));

// Promise.all برای چندین Promise
const promise1 = Promise.resolve(3);
const promise2 = new Promise(resolve => setTimeout(() => resolve('foo'), 1000));
const promise3 = Promise.resolve(42);

Promise.all([promise1, promise2, promise3])
    .then(values => console.log(values)); // [3, "foo", 42]

Async/Await

// تابع async
async function fetchData() {
    try {
        const response = await fetch('https://api.example.com/data');
        const data = await response.json();
        return data;
    } catch (error) {
        console.error('خطا در دریافت داده:', error);
        throw error;
    }
}

// استفاده از async function
async function processData() {
    try {
        const data = await fetchData();
        console.log('داده دریافت شد:', data);
    } catch (error) {
        console.log('خطا در پردازش:', error);
    }
}

// Promise.all با async/await
async function fetchMultipleData() {
    try {
        const [users, posts, comments] = await Promise.all([
            fetch('/api/users').then(r => r.json()),
            fetch('/api/posts').then(r => r.json()),
            fetch('/api/comments').then(r => r.json())
        ]);
        
        return { users, posts, comments };
    } catch (error) {
        console.error('خطا در دریافت داده‌ها:', error);
    }
}

تمرین عملی: مفاهیم پیشرفته

در ادامه، مفاهیم پیشرفته JavaScript را تمرین کنید:

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

Prototypes و وراثت

JavaScript از prototype-based inheritance استفاده می‌کند:

Constructor Functions

function Person(name, age) {
    this.name = name;
    this.age = age;
}

// اضافه کردن متد به prototype
Person.prototype.greet = function() {
    return `سلام، من ${this.name} هستم`;
};

Person.prototype.getAge = function() {
    return this.age;
};

const person1 = new Person('علی', 25);
console.log(person1.greet()); // "سلام، من علی هستم"

وراثت با Prototypes

// کلاس پایه
function Animal(name) {
    this.name = name;
}

Animal.prototype.speak = function() {
    return `${this.name} صدا می‌کند`;
};

// کلاس مشتق
function Dog(name, breed) {
    Animal.call(this, name); // فراخوانی constructor والد
    this.breed = breed;
}

// تنظیم وراثت
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;

// متد اختصاصی
Dog.prototype.bark = function() {
    return `${this.name} واق واق می‌کند`;
};

const dog = new Dog('رکس', 'ژرمن');
console.log(dog.speak()); // "رکس صدا می‌کند"
console.log(dog.bark()); // "رکس واق واق می‌کند"

ES6 Classes

class Vehicle {
    constructor(brand, model) {
        this.brand = brand;
        this.model = model;
    }
    
    getInfo() {
        return `${this.brand} ${this.model}`;
    }
    
    start() {
        return `${this.getInfo()} روشن شد`;
    }
}

class Car extends Vehicle {
    constructor(brand, model, doors) {
        super(brand, model);
        this.doors = doors;
    }
    
    getInfo() {
        return `${super.getInfo()} با ${this.doors} در`;
    }
    
    honk() {
        return `${this.brand} بوق زد`;
    }
}

const car = new Car('تویوتا', 'کمری', 4);
console.log(car.start()); // "تویوتا کمری با 4 در روشن شد"

Module Pattern

الگوهای مختلف برای سازماندهی کد:

IIFE (Immediately Invoked Function Expression)

const MyModule = (function() {
    // متغیرهای خصوصی
    let privateVar = 'متغیر خصوصی';
    let counter = 0;
    
    // توابع خصوصی
    function privateFunction() {
        return 'تابع خصوصی';
    }
    
    // API عمومی
    return {
        publicMethod: function() {
            return `دسترسی به ${privateVar}`;
        },
        increment: function() {
            return ++counter;
        },
        getCounter: function() {
            return counter;
        }
    };
})();

console.log(MyModule.publicMethod()); // "دسترسی به متغیر خصوصی"
console.log(MyModule.increment()); // 1

Revealing Module Pattern

const RevealingModule = (function() {
    let privateCounter = 0;
    
    function privateIncrement() {
        privateCounter++;
    }
    
    function privateDecrement() {
        privateCounter--;
    }
    
    function publicGetCount() {
        return privateCounter;
    }
    
    function publicReset() {
        privateCounter = 0;
    }
    
    // فقط متدهای عمومی را نمایش می‌دهیم
    return {
        increment: privateIncrement,
        decrement: privateDecrement,
        getCount: publicGetCount,
        reset: publicReset
    };
})();

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

Generators

function* numberGenerator() {
    let num = 1;
    while (true) {
        yield num++;
    }
}

function* fibonacciGenerator() {
    let a = 0, b = 1;
    while (true) {
        yield a;
        [a, b] = [b, a + b];
    }
}

const numbers = numberGenerator();
console.log(numbers.next().value); // 1
console.log(numbers.next().value); // 2

const fibonacci = fibonacciGenerator();
for (let i = 0; i < 5; i++) {
    console.log(fibonacci.next().value); // 0, 1, 1, 2, 3
}

Symbols

// ایجاد Symbol
const sym1 = Symbol('description');
const sym2 = Symbol('description');
console.log(sym1 === sym2); // false

// Global Symbol Registry
const sym3 = Symbol.for('global');
const sym4 = Symbol.for('global');
console.log(sym3 === sym4); // true

// استفاده در اشیاء
const obj = {
    [sym1]: 'مقدار خصوصی',
    normalProp: 'مقدار عادی'
};

console.log(Object.keys(obj)); // ['normalProp']
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(description)]

Proxy و Reflect

const target = {
    name: 'علی',
    age: 25
};

const handler = {
    get: function(obj, prop) {
        console.log(`دسترسی به ویژگی: ${prop}`);
        return prop in obj ? obj[prop] : `ویژگی ${prop} وجود ندارد`;
    },
    
    set: function(obj, prop, value) {
        console.log(`تنظیم ویژگی ${prop} به ${value}`);
        if (prop === 'age' && typeof value !== 'number') {
            throw new TypeError('سن باید عدد باشد');
        }
        Reflect.set(obj, prop, value);
        return true;
    }
};

const proxy = new Proxy(target, handler);
console.log(proxy.name); // "دسترسی به ویژگی: name" -> "علی"
proxy.age = 26; // "تنظیم ویژگی age به 26"

بهینه‌سازی عملکرد

Debouncing

function debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
        const later = () => {
            clearTimeout(timeout);
            func(...args);
        };
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
    };
}

// استفاده برای جستجو
const searchInput = document.getElementById('search');
const debouncedSearch = debounce(function(e) {
    console.log('جستجو برای:', e.target.value);
    // انجام جستجو
}, 300);

searchInput.addEventListener('input', debouncedSearch);

Memoization

function memoize(fn) {
    const cache = {};
    return function(...args) {
        const key = JSON.stringify(args);
        if (key in cache) {
            return cache[key];
        }
        const result = fn.apply(this, args);
        cache[key] = result;
        return result;
    };
}

// مثال: محاسبه فیبوناچی
function fibonacci(n) {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
}

const memoizedFibonacci = memoize(fibonacci);
console.log(memoizedFibonacci(40)); // سریع‌تر از حالت عادی

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

💡 نکات مهم:

  • Memory Management: از memory leaks جلوگیری کنید
  • Error Handling: همیشه خطاها را مدیریت کنید
  • Performance: از تکنیک‌های بهینه‌سازی استفاده کنید
  • Code Organization: از Module Pattern استفاده کنید
  • Testing: کد خود را تست کنید

مدیریت خطا

// Global error handler
window.addEventListener('error', function(e) {
    console.error('خطای سراسری:', e.error);
});

// Promise rejection handler
window.addEventListener('unhandledrejection', function(e) {
    console.error('Promise رد شده:', e.reason);
    e.preventDefault(); // جلوگیری از نمایش خطا در console
});

// Try-catch with async/await
async function safeAsyncFunction() {
    try {
        const result = await riskyAsyncOperation();
        return result;
    } catch (error) {
        console.error('خطا در عملیات async:', error);
        throw new Error('عملیات ناموفق بود');
    } finally {
        console.log('تمیزکاری انجام شد');
    }
}

آزمون درس ۱۹

سوال ۱: Closure چیست؟

سوال ۲: کدام کلیدواژه برای انتظار Promise استفاده می‌شود؟

سوال ۳: IIFE مخفف چیست؟