spread و rest در جاوا اسکریپت


تا حالا به احتمال زیاد three dots (…) رو در کدهای جاوا اسکریپت دیدید.آیا میدونستید که این syntax برای دو ویژگی متفاوت جاوا اسکریپت مورد استفاده قرار میگیره؟
در این مقاله نحوه استفاده های مختلف از این دو ویژگی رو یاد میگیرید و متوجه می شوید که چقدر کدهای شما با استفاده از rest و spread خواناتر،مختصرتر و زیباتر می شود.
یک syntax، دو ویژگی متفاوت
rest و spread دو ویژگی متفاوت هستند که در EcmaScript 2015 قرار گرفتند.در ادامه شما خواهید دید که این ویژگی ها به طور وارونه رفتار می کنند و غالبا میشه به عنوان مکمل یکدیگر استفاده شوند.
حالا بیایید چک کنیم که هر کدوم چه کاری انجام میدن.
Spread
قبل از اینکه spread operator رو توضیح بدیم،اجازه بدید که مثالی رو بررسی کنیم که میتونه برای بحث ما مفید باشه:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
const config = { height: 200, width: 400, backgroundColor: 'white', title: 'Just an ordinary window', content: 'something nice...' }; showModalWindow(config); function showModalWindow(config) { const windowConfig = { modal: true, showBackdrop: true, height: config.height, width: config.width, backgroundColor: config.backgroundColor, title: config.title, content: config.content }; // The remaining logic is not relevant for the purpose of this article } |
تیکه کد بالا شامل یک تابع می شود که یک modal را نمایش می دهد.این تابع یک configuration object به عنوان ورودی دریافت می کند که بر اساس اون modal نمایش داده می شود.همچنین درون تابع یک configuration object جدید ساخته می شود که با ترکیب اطلاعات دریافتی مشخص می شود که modal با چه ویژگی هایی نمایش داده شود.
همانطور که متوجه شدید برای استفاده از اطلاعات configuration object دریافتی در configuration object جدید تمامی گزینه ها به صراحت کپی شده اند و اگر گزینه بیشتر باشد،اوضاع خیلی بدتر خواهد بود چون باید تمامی موارد عینا کپی شود.
راه های مختلفی برای خلاصه تر کردن این کد وجود دارد:
- استفاده از Object.assign
- استفاده از spread operator
استفاده از spread operator در objects
حالا به ورژن جدید تابع از مثال بالای نگاه کنید:
1 2 3 4 5 6 7 8 9 |
function showModalWindow(config) { const windowConfig = { modal: true, showBackdrop: true, ...config }; // The remaining logic is not relevant for the purpose of this article } |
پس از استفاده از spread و تغییر تمامی properties های object دریافتی در configuration object جدید قرار می گیرند.همونطور که می بینید کد ما خیلی خواناتر، کوتاه تر و بسیار انعطاف پذیرتر شده است.
نکته مهم در اینجا این است که شما شاید گاهی اوقات نیاز داشته باشید که بر روی پارامتر دریافتی یک سری فیلتر ها انجام دهید چون فقط می خواهید که برخی از properties ها فقط اعمال شوند.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
const config = { height: 200, width: 400, backgroundColor: 'white', title: 'Just an ordinary window', unwantedConfig: 'this should not be allowed to pass' }; showModalWindow(config); function showModalWindow(config) { const filteredConfig = // implement some filtering logic here... const windowConfig = { modal: true, showBackdrop: true, ...filteredConfig }; } |
استفاده از spread operator در arrays
شما میتونید از spread operator در آرایه ها استفاده کنید.در حقیقت در ES2015 شما فقط میتونستید از spread در آرایه ها استفاده کنید(پشتیبانی از objects در ES2018 معرفی شد)
1 2 3 4 5 |
onst n1 = [99, 88, 77]; const n3 = [33, 22, 11]; const n2 = [...n1, 66, 55, 44, ...n3]; console.log(n2); //=> [99, 88, 77, 66, 55, 44, 33, 22, 11] |
آیتم های آرایه های n1 و n3 در ابتدا و انتها n2 قرار می گیرند.این مقادیر با 66, 55 و 44 که در ابتدا به عنوان مقادیر اولیه آرایه n2 قرار گرفته بود، ترکیب می شوند.
در مثال زیر 3 آرایه در یک آرایه جدید ترکیب می شوند.
1 2 3 4 |
const signUpStatuses = ['SIGNUP_BASIC_INFO', 'SIGNUP_PAYMENT_INFO', 'SIGNUP_CONTACT_INFO']; const analysisStatuses = ['PENDING_ANALYSIS', 'REJECTED', 'PENDING_DOCUMENTATION']; const postApprovalStatuses = ['ACTIVE', 'SUSPENDED', 'BLACKLIST']; const statuses = [...signUpStatuses, ...analysisStatuses, ...postApprovalStatuses]; |
حتی شما می توانید با استفاده از spread یک آرایه رو به یک object تبدیل کنید.با انجام این کار آیتم های آرایه Value و indexes آرایه key خواهند بودپ
1 2 3 4 |
const monthsArr = ['January', 'February', 'March', 'April']; const monthsObj = { ...monthsArr }; console.log(monthsObj); //=> { 0: "January", 1: "February", 2: "March", 3: "April" } |
استفاده از spread operator در function calls
همچنین میتوان از spread operator در فراخوانی توابع استفاده کرد.در واقع میتوان با استفاده از این ویژگی آیتم های یک آرایه رو به عنوان arguments به یک تابع پاس داد.در ادامه برای نشان دادن این ویژگی چندین مثال رو بررسی می کنیم:
1 2 |
const ids = [11, 12, 13, 14, 15]; retrieveItemsByIds(...ids); |
مثال بالا یک تابع را فراخوانی می کند و 5 عدد از آرایه ids به عنوان arguments پاس میدهد.این کد معادل :
1 |
retrieveItemsByIds(11, 12, 13, 14, 15); |
اگر میخواهید که بیشتر با این مورد سروکله بزنید کافیه که کنسول مرورگر خود را باز کنید و این آرایه رو console.log کنید
1 |
console.log(...ids); |
اکنون به مثال زیر نگاه کنید:
1 2 3 4 5 6 7 8 9 10 11 12 |
const pixels = [ [10, 25, '#DDD'], [11, 26, '#CCC'], [12, 27, '#BBB'], [13, 28, '#AAA'], [14, 29, '#999'], ]; pixels.forEach(pixel => drawPixel(...pixel)); function drawPixel(x, y, color) { // pixel drawing logic comes here |
این بار ما یک آرایه دو بعدی ایجاد می کنیم و برای هر کدام از عناصر آرایه تابع drawPixel رو فراخوانی می کنیم و آیتم ها رو به عنوان arguments برای این فراخوانی پاس میدیم.توجه داشته باشید برای اینکه arguments به درستی پاس داده شده باشند، مقادیر sub-arrays(زیرآرایه ها) به ترتیب x coordinate, y coordinate و color هستند.
Rest
به جرات میتوان گفت با اینکه rest و spread یک syntax دارند ولی کارهای متفاوتی را انجام می دهند.همانطور که در بالا دیدید میتوان از spread operator برای پخش کردن(کپی کردن) آیتم آرایه ها و اشیاء در آرایه ها و اشیاء دیگر استفاده کرد.اما Rest آیتم های مربوط به آرایه را در یک آرایه جدید و properties های یک object را در object جدید قرار می دهد.
Using rest in destructuring assignment
هرچند که در این مقاله تمرکز بر روی destructuring assignment نیست اما یک قطعه کد ساده که نحوه کار آن را نشان می دهد در اینجا قرار گرفته است:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// Destructuring assignment for arrays const ipOctets = [192, 168, 0, 1]; const [octet1, octet2, octet3, octet4] = ipOctets; console.log('First octet:', octet1); //=> First octet: 192 console.log('Second octet:', octet2); //=> Second octet: 168 console.log('Third octet:', octet3); //=> Third octet: 0 console.log('Fourth octet:', octet4); //=> Fourth octet: 1 // Destructuring assignment for objects const person = { firstName: 'John', lastName: 'Doe', age: 42 }; const { firstName, lastName, age } = person; console.log('First name: ', firstName); //=> John console.log('Last name: ', lastName); //=> Doe console.log('Age: ', age); //=> 42 |
به طور خلاصه این ویژگی این امکان را در اختیار شما می گذارد تا آیتم های یک آرایه و properties یک object را در متغیرهای individual قرار دهید. اگر با مفهوم destructuring آشنا نیستید پیشنهاد میکنم مقاله 4 ویژگی مدرن جاوا اسکریپت که باید از آن استفاده کنید رو حتما بخونید.
ما میتوانیم از rest با destructuring assignment استفاده کنیم.بیایید در ابتدا یک مثال با object را بررسی کنیم:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
const user = { name: 'Frederick Charles Krueger', motherName: 'Amanda Krueger', age: 80, address: '1428 Elm Street' }; const { address, ...personalInfo } = user; console.log('Address:', address); //=> 1428 Elm Street console.log(personalInfo); /* => { age: 80, motherName: "Amanda Krueger", name: "Frederick Charles Krueger" } */ |
در مثال بالا ما یک property از user object رو به یک متغیر(address) extract کردیم و بقیه properties ها رو در یک object جدید به نام personalInfo قرار دادیم که این object شامل address نمی باشد.
حالا به مثال زیر که با آرایه است نگاه کنید:
1 2 3 4 5 6 7 |
const ranking = ['ALC', 'QUE', 'JNS', 'BMX', 'TAK', 'SHI', 'BAT', 'CFO', 'ACE', 'CAT']; const [first, second, third, ...others] = ranking; console.log('1st place:', first); //=> "1st place: ALC" console.log('2nd place:', second); //=> "2nd place: QUE" console.log('3rd place:', third); //=> "3rd place: JNS" console.log('Honorable mentions:', others.join(', ')); //=> "Honorable mentions: BMX, TAK, SHI, BAT, CFO, ACE, CAT" |
منطق این قطعه کد مانند مثال بالایی است.ما 3 آیتم اولی آرایه ranking رو در 3 متغیر متفاوت و مابقی را در یک آرایه دیگر دخیره کردیم.
شاید شما متوجه شده باشید که استفاده از syntax rest فقط در انتها destructuring assignment قابل استفاده است.نتیجه مثتل پایین با error روبرو می شود:
1 2 |
const codes = [11, 22, 33, 44, 55]; const [first, ...others, last] = codes; |
Using rest in a function signature
شما می توانید از چندین متغیر به عنوان پارامتر های اولیه یک تابع استفاده کنید و مابقی پارامترها رو در یک آرایه قرار دهید.میتوان گفت که rest در اینجا به عنوان destructuring آرایه ها عمل می کند:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
function printRanking(first, second, third, ...others) { console.log('1st place:', first); console.log('2nd place:', second); console.log('3rd place:', third); console.log('Honorable mentions:', others.join(', ')); } printRanking('ALC', 'QUE', 'JNS', 'BMX', 'TAK', 'SHI', 'BAT', 'CFO', 'ACE', 'CAT'); /* => "1st place: ALC" => "2nd place: QUE" => "3rd place: JNS" => "Honorable mentions: BMX, TAK, SHI, BAT, CFO, ACE, CAT" */ |
و در این case که شما arguments ها رو در یک آرایه دارید، میتوانید از rest در فراخوانی تابع استفاده کنید:
1 2 |
const ranking = ['ALC', 'QUE', 'JNS', 'BMX', 'TAK', 'SHI', 'BAT', 'CFO', 'ACE', 'CAT']; printRanking(...ranking); |
به این ترتیب میتوانید از rest و spread به عنوان مکمل یکدیگر استفاده کنید.
نتیجه گیری:
- … syntax در جاوا اسکریپت برای دو ویژگی spread و rest که در ES2015 معرفی شد، استفاده می شوند.
- spread operator آیتم های آرایه رو در یک آرایه دیگر یا حتی در یک object دیگر (با استفاده از indexes به عنوان keys) و properties از یک object در یک object دیگر کپی می کند.همچنین میتواند عناصر یک آرایه را بر ترتیب به عنوان arguments یک تابع قرار دهد.
- destructuring assignment به شما اجازه می دهد تا مقادیر properties از یک object رو به متغیرهای متفاوتی اختصاص دهید که یک syntax خیلی خلاصه است.همچنین با آرایه ها نیز این اتفاق می افتد، و این امکان را می دهد که مقادیر را از یک آرایه داده شده به صورت متوالی در متغیرهای جداگانه extract کنید.
- با استفاده از rest شما می توانید پارامترهای یک تابع رو در یک آرایه نگه دارید.همچنین میتوان برخی از پارامتر های اولیه تابع رو به صورت عادی پاس داد و مابقی به صورت یک آرایه به تابع پاس داده شود.
اگر قصد یادگیری جاوا اسکریپت (javascript) به صورت حرفه ای و تخصصی را دارید، پیشنهاد می کنم آموزش مقدماتی تا پیشرفته جاوا اسکریپت(javascript) که کاملا پروژه محور است را تماشا کنید.
منبع : بلاگ مشفق همدانی
دیدگاهتان را بنویسید