متد filter در جاوااسکریپت دقیقاً همان کاری را انجام میدهد که از نامش پیداست؛ این متد یک آرایه را بر اساس شرطی که تعریف میکنیم فیلتر میکند و آرایهای جدید شامل المنتهایی را برمیگرداند که آن شرط را برآورده میکنند.
در این مقاله، با نحوه عملکرد متد
filter()
، کاربردهای عملی آن، تکنیکهای پیشرفته و بهترین شیوهها آشنا میشویم تا بتوانیم منطق فیلتر کردن دادهها را بهشکلی مؤثر و بهینه پیادهسازی کنیم.
ساختار کلی استفاده از متد
filter()
به این شکل است:
const newArray = originalArray.filter(callbackFunction(element,index, array),thisArg);
این متد پارامترهای زیر را دریافت میکند:
callbackFunction
: تابعی است که شرط فیلتر را مشخص میکند. این تابع برای هر المنت از آرایه، یک بار اجرا میشود.
element
: المنتی از آرایه که در حال حاضر در حال پردازش است.index
(اختیاری): شماره ایندکس المنت فعلی در آرایه میباشد، که از صفر شروع میشود.array
(اختیاری): خود آرایه اصلی که قرار است فیلتر شود.callbackFunction
باید یک مقدار بولین (true
یا false
) برگرداند. اگر مقدار بازگشتی true
باشد، آن المنت در آرایه جدید قرار میگیرد.thisArg
(اختیاری): مقداری که بهعنوان this
درون تابع callbackFunction
استفاده میشود. اگر از arrow functionها استفاده کنیم، این پارامتر نادیده گرفته میشود، چون arrow functionها this
مختص به خود ندارند.filter()
یک آرایه جدید برمیگرداند که فقط شامل المنتهایی است که شرط مشخص شده را برآورده میکنند.نکته: اگر هیچ المنتی شرایط مشخص شده را برآورده نکند، متد
filter()
یک آرایه خالی return میکند.
برای درک بهتر فرآیند متد filter در جاوااسکریپت،مثال سادهای را بررسی میکنیم که هم بدون استفاده از
filter()
نوشته شده و هم با استفاده از آن.
فرض کنید آرایهای از کلمات داریم و میخواهیم فقط کلماتی را نگه داریم که بیشتر از پنج حرف دارند. بدون استفاده از
filter()
، معمولاً با استفاده از یک حلقه for
به شکل زیر عمل میکنیم:
const words = ["apple", "banana", "kiwi", "pomegranate", "grape"]; const longwords = []; for (let i = 0; i < words.length; i++) { if (words[i].length > 5) { longwords.push(words[i]); } } console.log(longwords); //['banana', 'pomegranate']
در مثال بالا، لازم است بهصورت دستی از طریق حلقه، هر المت را بررسی کرده و اگر شرط برقرار بود، آن را به آرایه جدید اضافه نماییم.
اکنون، همین منطق را با استفاده از متد
filter()
سادهتر میکنیم:
const words = ["apple", "banana", "kiwi", "pomegranate", "grape"]; const longwords = words.filter((word) => word.length > 5); console.log(longwords); //['banana', 'pomegranate']
متد
filter()
خودش بهصورت داخلی عمل «تکرار» را انجام میدهد و نیازی به استفاده از حلقه for
نیست. بر اساس نتیجه تابع callback، هر المنت بهصورت خودکار به آرایه جدید اضافه میشود.
نکته: متد
filter()
فقط روی آرایهها کاربرد دارد. اگر بخواهیم آن را روی نوعهای دادهای دیگر در جاوااسکریپت اعمال کنیم، ابتدا باید آن دادهها را به آرایه تبدیل نماییم.
این متد در حل بسیاری از مسائل منطقی در پروژههای واقعی قابل استفاده است. در ادامه، چند مورد از رایجترین کاربردهای آن را بررسی میکنیم:
مثالی را بررسی میکنیم که در آن میخواهیم از میان لیستی از قیمت محصولات، فقط قیمتهایی که بالاتر از یک مقدار مشخص هستند را انتخاب نماییم.
برای این کار، میتوانیم از یک arrow function برای تعریف شرط فیلتر بهصورت مختصر استفاده کنیم.
const productPrices = [15.99, 25.50, 10.00, 30.75, 5.49, 22.00]; const expensiveProducts = productPrices.filter(price => price > 20); console.log(expensiveProducts) // Result: [25.5, 30.75, 22]
یکی از رایجترین کاربردهای متد filter در جاوااسکریپت، پیادهسازی قابلیت جستوجو است. این متد میتواند برای فیلتر کردن لیستی از نامها بر اساس یک عبارت جستوجو به کار رود، بهطوریکه فقط آیتمهای منطبق return شوند.
برای اطمینان از جستوجوی بدون حساسیت به حروف کوچک و بزرگ، بهتر است عبارت جستوجو و المنت آرایه را به حروف کوچک تبدیل کنیم، سپس فیلتر را اعمال نماییم:
const names = ['John', 'Alice', 'Jonathan', 'Bob', 'Joanna']; const searchQuery = 'jo'; const searchResults = names.filter(name => name.toLowerCase().includes(searchQuery.toLowerCase()) ); console.log(searchResults) // Result: ['John', 'Jonathan', 'Joanna']
متد
filter()
را میتوانیم روی آرایهای از آبجکتها به کار ببریم تا المنتها را بر اساس مقدار ویژگی خاصی فیلتر کنیم.
برای مثال، فرض کنید یک پلتفرم محتوایی داریم که هر پست بهصورت یک آبجکت شامل ویژگیهایی مانند
id
، title
و tags
تعریف شده است. اگر بخواهیم فقط پستهایی را نمایش دهیم که دارای برچسب "tech"
هستند، میتوانیم از filter()
برای استخراج آنها استفاده کنیم:
const posts = [ { id: 1, title: 'AI Breakthrough', tags: ['tech', 'science']}, { id: 2, title: 'Travel Guide', tags: ['lifestyle'] }, { id: 3, title: 'New JavaScript Framework', tags: ['tech'] }, ]; const techPosts = posts.filter(post => post.tags.includes('tech')) console.log(techPosts) // Result: [ // { id: 1, title: 'AI Breakthrough', tags: [ 'tech', 'science' ] }, // { id: 3, title: 'New JavaScript Framework', tags: [ 'tech' ] } // ]
هنگام کار با دادههای خام، معمولاً با مقادیر نامعتبر یا موارد خاص مواجه میشویم که باید پیش از پردازش حذف شوند. بهجای بررسی و پاکسازی دستی دادهها، میتوانیم با استفاده از متد
filter()
این کار را بهصورت مؤثر انجام دهیم:
const rawData = ["Hello", "", 42, null, undefined, "JavaScript"]; const cleanData = rawData.filter(item => item !== null && item !== undefined && item !== ''); console.log(cleanData); //Result: [ 'Hello', 42, 'JavaScript' ]
یک روش سادهتر برای حذف مقادیر ناخواسته، استفاده از
Boolean
بهعنوان تابع بازگشتی است. این روش تمام مقادیر falsy (مانند null
، undefined
، false
، ""
و NaN
) را حذف میکند:
const cleanData = rawData.filter(Boolean);
هنگام کار با آرایهها، تکرار مقادیر امری رایج است. چه ورودی از سمت کاربر باشد و چه از منابع خارجی، لازم است آنها را بهشکل مؤثری حذف کنیم. این کار را میتوانیم با ترکیب متد
filter()
و indexOf()
انجام دهیم:
const duplicates = [1, 2, 2, 3, 4, 4, 5]; const uniqueValues = duplicates.filter((item, index, arr) => arr.indexOf(item) === index //Compares the first occurrence index with the current index ); console.log(uniqueValues) // Result: [1, 2, 3, 4, 5]
متد
indexOf(item)
اولین ایندکس المنت مورد نظر را در آرایه پیدا میکند. با مقایسه این ایندکس با ایندکس فعلی، فقط اولین تکرار از هر المنت در آرایه باقی میماند.
این روش برای آرایههایی با مقادیر اولیه (مانند اعداد و رشتهها) بهخوبی عمل میکند، اما برای آبجکتها کاربرد ندارد، زیرا هر آبجکت، مرجعی یکتا دارد و مقایسه آنها از نظر ارجاعی صورت میگیرد.
پس از آشنایی با عملکرد متد filter در جاوااسکریپت، اکنون میتوانیم یک گام فراتر رفته و آن را با دیگر متدهای آرایهای مانند
map()
و reduce()
ترکیب نماییم. این فرآیند که با عنوان زنجیرهسازی (chaining) شناخته میشود، به توسعهدهندگان این امکان را میدهد که چندین متد را بهصورت متوالی و در یک جریان یکپارچه اجرا کنند.
در زبان جاوااسکریپت، بسیاری از متدها یک آرایه یا آبجکت جدید return میکنند که همین ویژگی، chaining متدها را امکانپذیر میسازد. با استفاده از این تکنیک میتوانیم پردازشهای پیچیدهتری را بدون نیاز به حلقههای جداگانه یا متغیرهای میانی انجام دهیم و در عین حال، کد را خواناتر و ساختیافتهتر نگه داریم.
پیش از بررسی chaining، مروری کوتاه بر عملکرد متدهای مورد استفاده خواهیم داشت:
filter()
: المنتهای آرایه را بر اساس یک شرط مشخص فیلتر کرده و فقط موارد معتبر را بازمیگرداند.map()
: المنتهای باقیمانده را تغییر داده و یک آرایه جدید با مقادیر اصلاحشده تولید میکند.reduce()
: مقادیر آرایه را به یک مقدار واحد (مانند مجموع، میانگین یا شمارش) تجمیع مینماید.در ادامه، نحوه ترکیب این متدها در سناریوهای کاربردی مورد بررسی قرار میدهیم.
یکی از رایجترین کاربردهای ترکیب
filter()
و map()
، پالایش دادههای دریافتی از API است. اغلب، پاسخهای دریافتی از سمت سرور حاوی مقادیر ناقص یا نامعتبر هستند. در چنین مواردی، با استفاده از زنجیرهسازی این دو متد میتوانیم ابتدا دادههای نامطلوب را حذف و سپس مقادیر باقیمانده را به فرمتی استاندارد تبدیل نماییم.
بهعنوان مثال، در یک سامانه مدیریت محتوا، ممکن است لیستی از مقالات از طریق API دریافت شود که برخی از آنها فاقد عنوان یا در وضعیت «پیشنویس» باشند. برای نمایش تنها مقالات منتشرشده با عنوان معتبر، میتوانیم از قطعه کد زیر استفاده کنیم:
const dummyData = [ { id: 1, title: ' JavaScript Guide ', status: 'DRAFT' }, { id: 2, title: 'React Basics', status: 'PUBLISHED' }, { id: 3, title: ' ', status: 'PUBLISHED' }, // Invalid title ]; const publishedArticles = dummyData .filter(item => item.title.trim() !== '' && item.status === 'PUBLISHED') // Remove empty titles and drafts .map(item => ({ ...item, // Copy all values from the original array title: item.title.trim().toLowerCase(), // Normalize title })); console.log(publishedArticles); // Result: [{ id: 2, title: 'react basics', status: 'PUBLISHED' }]
ترکیب متدهای
filter()
و reduce()
در مواقعی مفید است که لازم است ابتدا المنتهای خاصی از آرایه انتخاب کزده و سپس یک مقدار نهایی از آنها محاسبه نماییم.
برای مثال، فرض کنید در یک فروشگاه اینترنتی لیستی از محصولات موجود است که برخی از آنها در انبار موجود نیستند. هدف آن است که مجموع ارزش محصولات موجود در انبار را محاسبه کنیم. این کار از طریق فیلتر کردن محصولات موجود و جمع قیمت آنها قابل انجام است:
const products = [ { name: 'Laptop', price: 1000, inStock: true }, { name: 'Phone', price: 500, inStock: false }, { name: 'Tablet', price: 750, inStock: true }, ] const totalStockValue = products .filter((product) => product.inStock) // Keep only in-stock products .reduce((sum, product) => sum + product.price, 0) // Add up prices console.log(totalStockValue) // Result: 1750
با chaining متدهای آرایهای در جاوااسکریپت، میتوانیم عملیات پیچیده را با وضوح بالا و بهصورت مؤثر انجام دهیم، بدون آنکه خوانایی یا نگهداری کد تحتتأثیر قرار گیرد.
هرچند متد filter در جاوااسکریپت بسیار ساده و قابل فهم است، اما رعایت چند نکته کلیدی میتواند به بهینهتر شدن کد و افزایش قابلیت نگهداری آن کمک کند.
توصیه میشود منطق داخل تابع callback را ساده نگه داریم. از محاسبات سنگین یا عملیات پیچیده در این قسمت خودداری نماییم. در صورت امکان، مقادیر موردنیاز را از قبل محاسبه کرده و از توابع داخلی زبان استفاده کنیم تا عملکرد بهتری حاصل شود.
arrow functionها باعث کوتاهتر شدن کد، افزایش خوانایی و حذف کدهای تکراری میشوند. این موضوع در بهبود ساختار کلی پروژه نیز مؤثر خواهد بود.
زنجیرهسازی متدهایی مانند
filter()
، map()
و reduce()
روش مناسبی برای حذف متغیرهای میانی و حفظ انسجام کد است. با این حال، اگر زنجیره بیش از حد پیچیده شود، خوانایی آن کاهش مییابد. در چنین مواردی، پیشنهاد میشود بخشهای مختلف زنجیره را به توابع مجزا با نامهای گویا تقسیم کنیم تا درک و نگهداری کد آسانتر شود.
هنگام اعمال تغییر بر روی آبجکتها، باید مراقب باشیم که دادههای اولیه بهصورت ناخواسته دچار تغییر (mutation) نشوند. استفاده از عملگر spread (
...
) راهکاری مطمئن برای ساخت نسخههای جدید از آبجکتها است، بدون آنکه آبجکت اصلی دستخوش تغییر گردد.
در مواقعی که با مجموعهدادههای بسیار بزرگ سروکار داریم، ممکن است استفاده از حلقههای
for
در مقایسه با متد filter()
از نظر عملکرد بهتر باشد. هرچند متد filter()
خواناتر و مدرنتر است، اما در شرایط حساس به عملکرد، استفاده از حلقه بهینه میتواند انتخاب مناسبتری باشد.
در این مقاله، متد filter در آرایههای جاوااسکریپت را مورد بررسی قرار دادیم. از معرفی نحوه استفاده بیسیک تا تکنیکهای پیشرفته مانند chaining با
map()
و reduce()
، تلاش کردیم تصویری کامل از این ابزار قدرتمند ارائه دهیم.
با درک عمیق عملکرد این متد و رعایت نکات و شیوههای پیشنهادی، میتوانیم کدی بنویسیم که هم تمیزتر و خواناتر باشد و هم از نظر عملکردی بهینهتر عمل کند.