مقدمه
قبل از ES6، برای نوشتن یک callback ساده مجبور بودیم اینقدر بنویسیم:
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(function(num) {
return num * 2;
});
// فیلتر اعداد زوج
const evens = numbers.filter(function(num) {
return num % 2 === 0;
});
// جمع با reduce
const sum = numbers.reduce(function(acc, num) {
return acc + num;
}, 0);
با Arrow Function در ES6 همین کدها میشوند:
const doubled = numbers.map(num => num * 2);
const evens = numbers.filter(num => num % 2 === 0);
const sum = numbers.reduce((acc, num) => acc + num, 0);
خیلی کوتاهتر و خواناتر! اما Arrow Function فقط shorthand نیست — رفتار this در آن کاملاً متفاوت است و این مهمترین تفاوتش با تابع معمولی است.
Arrow Function چیست؟
Arrow Function یک روش مختصر برای تعریف توابع است که با علامت => نوشته میشود. به همین دلیل به آن Fat Arrow Function هم میگویند.
// سینتکس پایه
const functionName = (parameters) => {
// بدنه تابع
return value;
};
// مقایسه با تابع معمولی:
function add(a, b) { return a + b; } // Function Declaration
const add = function(a, b) { return a + b; }; // Function Expression
const add = (a, b) => { return a + b; }; // Arrow Function
const add = (a, b) => a + b; // Arrow Function — کوتاهترین حالت
سینتکسهای مختلف Arrow Function
۱. بدون پارامتر — پرانتز خالی الزامی
const greet = () => 'سلام کدلوپ!';
const getDate = () => new Date();
const random = () => Math.random();
const clearLog = () => { console.clear(); }; // با بدنه
console.log(greet()); // 'سلام کدلوپ!'
console.log(getDate()); // Date object
۲. یک پارامتر — پرانتز اختیاری
// پرانتز اختیاری — هر دو درست هستند
const double = num => num * 2;
const double2 = (num) => num * 2;
const square = n => n ** 2;
const isEven = n => n % 2 === 0;
const toString = n => String(n);
const toUpperCase = str => str.toUpperCase();
console.log(double(5)); // 10
console.log(square(4)); // 16
console.log(isEven(7)); // false
console.log(toUpperCase('hello')); // 'HELLO'
۳. چند پارامتر — پرانتز الزامی
const add = (a, b) => a + b;
const multiply = (a, b) => a * b;
const fullName = (first, last) => first + ' ' + last;
const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
console.log(add(3, 4)); // 7
console.log(fullName('رضا', 'احمدی')); // 'رضا احمدی'
console.log(clamp(150, 0, 100)); // 100
۴. بدنه چند خطی — از {} و return استفاده کنید
const calculateTotal = (price, quantity, discount) => {
const subtotal = price * quantity;
const discountAmount = subtotal * discount;
const total = subtotal - discountAmount;
const tax = total * 0.09;
return total + tax;
};
console.log(calculateTotal(100000, 3, 0.1)); // 294300
۵. بازگشت Object — حتماً پرانتز بگذارید
// ❌ اشتباه رایج — {} به عنوان بدنه تفسیر میشود
const getUser = (name) => { name: name, role: 'user' }; // undefined برمیگرداند!
// ✅ Object را داخل پرانتز بگذارید
const getUser = (name) => ({ name, role: 'user' });
const getArticle = (title, slug) => ({ title, slug, views: 0, createdAt: new Date() });
console.log(getUser('رضا')); // { name: 'رضا', role: 'user' }
console.log(getArticle('اسکوپ', 'javascript-scope')); // { title: 'اسکوپ', ... }
Implicit Return — بازگشت ضمنی
// وقتی بدنه تابع فقط یک expression است، {} و return را حذف کنید
// با return صریح
const square1 = (n) => { return n * n; };
// با implicit return — معادل
const square2 = (n) => n * n;
// مثالهای پرکاربرد در پروژههای واقعی
const isAdmin = user => user.role === 'admin';
const getTitle = article => article.title;
const formatDate = date => new Date(date).toLocaleDateString('fa-IR');
const toSlug = str => str.trim().toLowerCase().replace(/s+/g, '-');
// در Array Methods — کوتاه و خوانا
const articles = [
{ title: 'اسکوپ', views: 3100, published: true },
{ title: 'کلوژر', views: 2800, published: false },
{ title: 'Promise', views: 4200, published: true },
];
const titles = articles.map(a => a.title);
const published = articles.filter(a => a.published);
const totalViews = articles.reduce((sum, a) => sum + a.views, 0);
const mostPopular = articles.sort((a, b) => b.views - a.views)[0];
console.log(titles); // ['اسکوپ', 'کلوژر', 'Promise']
console.log(totalViews); // 10100
مهمترین تفاوت — رفتار this
این اصلیترین تفاوت Arrow Function با تابع معمولی است و باعث بیشترین سردرگمی میشود.
در تابع معمولی: this بستگی به نحوه فراخوانی دارد (Dynamic this).
در Arrow Function: this از محیط Lexical بیرونی میآید (Lexical this) — و قابل تغییر نیست.
// ─── مشکل کلاسیک با تابع معمولی ───
function Timer() {
this.seconds = 0;
setInterval(function() {
this.seconds++; // ❌ this اینجا window است، نه Timer!
console.log(this.seconds); // NaN
}, 1000);
}
// ─── راهحل قدیمی — ذخیره this در متغیر ───
function Timer() {
this.seconds = 0;
const self = this; // ذخیره this
setInterval(function() {
self.seconds++; // ✅ self همان Timer است
console.log(self.seconds); // 1, 2, 3, ...
}, 1000);
}
// ─── راهحل مدرن — Arrow Function ───
function Timer() {
this.seconds = 0;
setInterval(() => {
this.seconds++; // ✅ this از Timer میآید — Lexical this
console.log(this.seconds); // 1, 2, 3, ...
}, 1000);
}
const t = new Timer();
مقایسه this در Object Methods
const articleManager = {
siteName: 'codeloop.ir',
articles: ['اسکوپ', 'کلوژر', 'Promise'],
// ✅ Method معمولی — this = articleManager
printAll: function() {
this.articles.forEach(function(article) {
// ❌ this اینجا window است — نه articleManager!
console.log(this.siteName + ': ' + article);
});
},
// ✅ Arrow Function داخل Method — this از Method میآید
printAllFixed: function() {
this.articles.forEach((article) => {
// ✅ this = articleManager — Lexical this
console.log(this.siteName + ': ' + article);
});
},
// ❌ Arrow Function به عنوان Method — this مشکل دارد
getSiteName: () => {
return this.siteName; // ❌ this = window/undefined
},
// ✅ Method معمولی
getSiteNameFixed() {
return this.siteName; // ✅ this = articleManager
},
};
articleManager.printAll(); // codeloop.ir: undefined (مشکل)
articleManager.printAllFixed(); // codeloop.ir: اسکوپ / کلوژر / Promise ✅
جدول مقایسه کامل
ویژگی | تابع معمولی | Arrow Function |
|---|---|---|
سینتکس | function name() {} | const name = () => {} |
this | Dynamic — بستگی به فراخوانی | Lexical — از محیط بیرونی |
arguments | ✅ دارد | ❌ ندارد (از Rest استفاده کنید) |
new (Constructor) | ✅ میتوان استفاده کرد | ❌ نمیتوان — TypeError |
prototype | ✅ دارد | ❌ ندارد |
Hoisting | ✅ (فقط Declaration) | ❌ (مثل متغیر) |
implicit return | ❌ | ✅ |
bind/call/apply | ✅ this را تغییر میدهد | ❌ تأثیری ندارد |
Generator | ✅ function* | ❌ نمیتواند Generator باشد |
مناسب برای Method | ✅ | ❌ (this مشکل دارد) |
مناسب برای Callback | ✅ | ✅ (معمولاً بهتر) |
arguments در Arrow Function
// تابع معمولی — arguments object دارد
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(sum(1, 2, 3, 4)); // 10
// Arrow Function — arguments ندارد
const sum2 = () => {
console.log(arguments); // ❌ ReferenceError در strict mode
};
// ✅ راهحل — Rest Parameters
const sum3 = (...args) => args.reduce((acc, n) => acc + n, 0);
console.log(sum3(1, 2, 3, 4)); // 10
// ✅ یا برای نامگذاری بهتر
const calculateTotal = (...prices) => {
return prices.reduce((total, price) => total + price, 0);
};
console.log(calculateTotal(100000, 50000, 25000)); // 175000
bind، call و apply روی Arrow Function کار نمیکنند
const arrow = () => this;
const regular = function() { return this; };
const obj = { name: 'رضا' };
console.log(regular.call(obj)); // { name: 'رضا' } ✅
console.log(arrow.call(obj)); // window/undefined — this تغییر نکرد!
console.log(regular.bind(obj)()); // { name: 'رضا' } ✅
console.log(arrow.bind(obj)()); // window/undefined — بیتأثیر!
// این رفتار در Event Listener مهم است:
class Button {
constructor(text) {
this.text = text;
}
// ❌ Arrow Function — bind کار نمیکند
handleClickArrow = () => console.log(this.text); // ✅ اما Lexical this خودش درست است
// ✅ Method معمولی — نیاز به bind دارد
handleClickRegular() {
console.log(this.text);
}
}
const btn = new Button('ارسال');
document.addEventListener('click', btn.handleClickArrow); // ✅ this = btn
document.addEventListener('click', btn.handleClickRegular); // ❌ this = document
document.addEventListener('click', btn.handleClickRegular.bind(btn)); // ✅
کِی از Arrow Function استفاده کنیم؟
// ✅ ۱. Callback در Array Methods — ایدهآل
const articles = [
{ title: 'اسکوپ', views: 3100, category: 'javascript', published: true },
{ title: 'React', views: 4800, category: 'react', published: true },
{ title: 'Draft', views: 0, category: 'misc', published: false },
];
const result = articles
.filter(a => a.published && a.views > 1000)
.map(a => ({ title: a.title, views: a.views.toLocaleString() }))
.sort((a, b) => b.views - a.views);
// ✅ ۲. setTimeout / setInterval داخل Method
const poller = {
data: [],
start() {
setInterval(() => { // Arrow — this = poller ✅
this.data.push(new Date());
}, 1000);
},
};
// ✅ ۳. Promise chain
fetch('https://freeapi.codeloop.ir/products')
.then(res => res.json())
.then(data => data.filter(p => p.price > 500000))
.then(data => console.log(data.length + ' محصول گرانقیمت'))
.catch(err => console.error(err));
// ✅ ۴. توابع کوتاه utility
const formatPrice = price => price.toLocaleString('fa') + ' تومان';
const isPublished = article => article.status === 'published';
const getViewCount = article => article.viewsCount || 0;
// ❌ ۱. Method در Object — this مشکل دارد
const user = {
name: 'رضا',
greet: () => 'سلام ' + this.name, // ❌ this.name = undefined
greet2() { return 'سلام ' + this.name; }, // ✅
};
// ❌ ۲. Constructor Function
const Article = (title) => { this.title = title; };
new Article('test'); // ❌ TypeError: Article is not a constructor
// ✅ از function یا class استفاده کنید
function Article(title) { this.title = title; }
class Article { constructor(title) { this.title = title; } }
// ❌ ۳. وقتی به arguments نیاز دارید
const logger = () => console.log(arguments); // ❌
function logger() { console.log(arguments); } // ✅
// ❌ ۴. Generator Function
const gen = *() => yield 1; // ❌ SyntaxError
function* gen() { yield 1; } // ✅
// ❌ ۵. Event Listener که به this المان نیاز دارد
button.addEventListener('click', () => {
this.classList.add('active'); // ❌ this = window
});
button.addEventListener('click', function() {
this.classList.add('active'); // ✅ this = button
});
مثال کامل واقعی — پردازش دادههای codeloop.ir
// پردازش کامل دادههای مقالات با Arrow Function
const articles = [
{ id: 1, title: 'جاوااسکریپت چیست', category: 'javascript', views: 5200, readingTime: 8, tags: ['js', 'web'], published: true },
{ id: 2, title: 'اسکوپ و کلوژر', category: 'javascript', views: 3100, readingTime: 15, tags: ['js', 'advanced'], published: true },
{ id: 3, title: 'React چیست', category: 'react', views: 4800, readingTime: 10, tags: ['react', 'js'], published: true },
{ id: 4, title: 'Node.js چیست', category: 'nodejs', views: 1500, readingTime: 9, tags: ['node', 'backend'], published: true },
{ id: 5, title: 'Draft Article', category: 'misc', views: 0, readingTime: 5, tags: [], published: false },
];
// آمار کامل با Arrow Function
const stats = {
// فقط منتشر شدهها
published: articles.filter(a => a.published),
// بیشترین بازدید
mostViewed: articles.sort((a, b) => b.views - a.views)[0],
// میانگین زمان مطالعه
avgReading: Math.round(
articles.filter(a => a.published)
.reduce((sum, a) => sum + a.readingTime, 0) /
articles.filter(a => a.published).length
),
// گروهبندی بر اساس category
byCategory: articles.reduce((groups, a) => {
if (!groups[a.category]) groups[a.category] = [];
groups[a.category].push(a.title);
return groups;
}, {}),
// همه تگهای منحصربهفرد
allTags: [...new Set(articles.flatMap(a => a.tags))],
// خلاصه برای نمایش
summary: articles
.filter(a => a.published)
.map(({ title, category, views, readingTime }) => ({
title,
category,
views: views.toLocaleString('fa') + ' بازدید',
readingTime: readingTime + ' دقیقه',
})),
};
console.log('منتشر شده:', stats.published.length);
console.log('پربازدیدترین:', stats.mostViewed.title);
console.log('میانگین مطالعه:', stats.avgReading + ' دقیقه');
console.log('دستهبندیها:', stats.byCategory);
console.log('تگها:', stats.allTags);
💡 برای تمرین عملی
با استفاده از API رایگان فارسی کدلوپ Arrow Function را تمرین کنید:
تمرین ۱ — پردازش محصولات
async function analyzeProducts() {
const products = await fetch('https://freeapi.codeloop.ir/products')
.then(r => r.json());
// همه با Arrow Function
const inStock = products.filter(p => p.inStock);
const expensive = products.filter(p => p.price > 1000000);
const names = products.map(p => p.name);
const totalValue = products.reduce((sum, p) => sum + p.price, 0);
const avgPrice = Math.round(totalValue / products.length);
console.log('موجود:', inStock.length);
console.log('گرانقیمت:', expensive.length);
console.log('میانگین قیمت:', avgPrice.toLocaleString('fa') + ' تومان');
console.log('نامها:', names.slice(0, 3));
}
analyzeProducts();
تمرین ۲ — Event Handler با Arrow Function
class SearchManager {
constructor() {
this.query = '';
this.results = [];
this.loading = false;
}
// Arrow Function به عنوان method — this همیشه درست است
handleInput = (e) => {
this.query = e.target.value;
this.search();
}
handleClear = () => {
this.query = '';
this.results = [];
document.querySelector('#search').value = '';
}
search = async () => {
if (!this.query.trim()) return;
this.loading = true;
const data = await fetch(
'https://freeapi.codeloop.ir/products?search=' + this.query
).then(r => r.json());
this.results = data.filter(p => p.name.includes(this.query));
this.loading = false;
console.log('نتایج برای "' + this.query + '":', this.results.length);
}
}
const manager = new SearchManager();
document.querySelector('#search').addEventListener('input', manager.handleInput);
document.querySelector('#clear').addEventListener('click', manager.handleClear);
تمرین ۳ — Pipeline پردازش داده
// Pipeline با Arrow Function — خوانا و قابل ترکیب
const pipe = (...fns) => (value) => fns.reduce((v, fn) => fn(v), value);
// توابع پردازش — هر کدام یک Arrow Function
const onlyInStock = products => products.filter(p => p.inStock);
const sortByPrice = products => [...products].sort((a, b) => a.price - b.price);
const top5 = products => products.slice(0, 5);
const formatForDisplay = products => products.map(p => ({
name: p.name,
price: p.price.toLocaleString('fa') + ' تومان',
}));
// ترکیب pipeline
const getTop5AffordableInStock = pipe(
onlyInStock,
sortByPrice,
top5,
formatForDisplay
);
fetch('https://freeapi.codeloop.ir/products')
.then(r => r.json())
.then(getTop5AffordableInStock)
.then(result => console.log('۵ محصول ارزانقیمت موجود:', result))
.catch(err => console.error(err));
اشتباهات رایج
/* ─── اشتباه ۱: Arrow Function به عنوان Method در Object ─── */
const counter = {
count: 0,
increment: () => {
this.count++; // ❌ this = window — count تغییر نمیکند!
},
};
counter.increment();
console.log(counter.count); // 0 — تغییر نکرد!
// ✅ Method Shorthand
const counter2 = {
count: 0,
increment() { this.count++; }, // ✅
};
/* ─── اشتباه ۲: فراموش کردن پرانتز دور Object ─── */
const getArticle = id => { id, title: 'test' }; // ❌ undefined
const getArticle2 = id => ({ id, title: 'test' }); // ✅
/* ─── اشتباه ۳: return فراموش شده در بدنه چند خطی ─── */
const greet = name => {
'سلام ' + name; // ❌ return فراموش شد — undefined
};
const greet2 = name => {
return 'سلام ' + name; // ✅
};
const greet3 = name => 'سلام ' + name; // ✅ implicit return
/* ─── اشتباه ۴: استفاده در Event Listener که به this المان نیاز دارد ─── */
document.querySelectorAll('.btn').forEach(btn => {
btn.addEventListener('click', () => {
this.classList.toggle('active'); // ❌ this = window
});
btn.addEventListener('click', function() {
this.classList.toggle('active'); // ✅ this = btn
});
});
/* ─── اشتباه ۵: Arrow Function به عنوان Constructor ─── */
const Person = (name) => { this.name = name; };
new Person('رضا'); // ❌ TypeError: Person is not a constructor
نکات مهم
Lexical this — مهمترین ویژگی Arrow Function است. this از محیط بیرونی میآید و با bind، call یا apply قابل تغییر نیست.
بدون prototype — Arrow Function پروتوتایپ ندارد، پس نمیتوان با new از آن استفاده کرد.
implicit return — فقط وقتی بدنه یک expression است. اگر از {} استفاده کردید، باید return بنویسید.
Object literal با پرانتز — برای بازگشت Object با implicit return، آن را داخل () بگذارید.
قانون کلی — از Arrow Function برای Callback، async/await و توابع کوتاه استفاده کنید. برای Method های Object و Constructor از تابع معمولی استفاده کنید.
نتیجهگیری
Arrow Function یکی از پرکاربردترین ویژگیهای ES6 است که کد جاوااسکریپت را کوتاهتر و خواناتر میکند. اما قدرت اصلی آن در Lexical this است — نه فقط در سینتکس مختصر.
قانون ساده برای انتخاب:
Callback، Array Methods، Promise chain، setTimeout → Arrow Function
Method در Object، Constructor، Event Listener که به this المان نیاز دارد → تابع معمولی
Arrow Function در React، Vue، Node.js و تقریباً هر فریمورک مدرنی همه جا استفاده میشود. وقتی Lexical this را کاملاً درک کنید، میفهمید چرا React Hooks به این شکل طراحی شدهاند و چرا در useEffect از Arrow Function استفاده میکنیم.
مقالات مرتبط
تابع در جاوااسکریپت — پایهی درک Arrow Function
اسکوپ و کلوژر در جاوااسکریپت — Lexical Scope که Arrow Function از آن استفاده میکند
ES6 در جاوااسکریپت چیست؟ — Arrow Function یکی از مهمترین ویژگیهای ES6 است
map، filter و reduce در جاوااسکریپت — Arrow Function در این متدها بسیار پرکاربرد است
Promise در جاوااسکریپت — Arrow Function در Promise chain ضروری است

