درس ۱۹: مفاهیم پیشرفته 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('تمیزکاری انجام شد');
}
}