کلون (Clone) کردن آرایه در جاوا اسکریپت — راهنمای مقدماتی
در جاوا اسکریپت برای انجام کارهای مختلف، روشهای گوناگونی وجود دارند. در این نوشته به روشهای متفاوتی میپردازیم که میتوان یک آرایه را در جاوا اسکریپت Clone کرد.
1. عملگر Spread (کپی سطحی)
از زمانی که استاندارد ES6 معرفی شده است؛ عملگر Spread پراستفادهترین گزینه محسوب میشود.
این روش ساختار خلاصهای دارد و در مواردی که از کتابخانهای مانند React و Redux استفاده میکنید بسیار مفید خواهد بود:
1numbers = [1, 2, 3];
2numbersCopy = [...numbers];
نکته: در این روش امکان کپی آرایههای چندبعدی وجود ندارد و مقادیر آرایه/شیء به جای کپی «با مقدار» (By Value) با روش «با ارجاع» (by Reference) کپی میشود. بنابراین کد زیر صحیح است:
1numbersCopy.push(4);
2console.log(numbers, numbersCopy);
3// [1, 2, 3] and [1, 2, 3, 4]
4// numbers is left alone
اما کد زیر درست نیست:
1nestedNumbers = [[1], [2]];
2numbersCopy = [...nestedNumbers];
3numbersCopy[0].push(300);
4console.log(nestedNumbers, numbersCopy);
5// [[1, 300], [2]]
6// [[1, 300], [2]]
7// They've both been changed because they share references
2. روش قدیمی حلقه ()for (کپی سطحی)
با توجه به رواج برنامهنویسی تابعی در این روزها، این روش احتمالاً از کمترین اقبال برخوردار است. در هر صورت این روش چه به صورت محض یا غیر محض، و چه به صورت اعلانی یا دستوری کار خود را به انجام میرساند.
1numbers = [1, 2, 3];
2numbersCopy = [];
3for (i = 0; i < numbers.length; i++) {
4 numbersCopy[i] = numbers[i];
5}
نکته: این روش آرایههای چندبعدی را به طور امنی کپی نمیکند. از آنجا که در این روش از عملگر = استفاده میشود، اشیا/آرایهها به جای روش «با مقدار» به صورت «با ارجاع» انتساب خواهند یافت.
کد زیر صحیح است:
1numbersCopy.push(4);
2console.log(numbers, numbersCopy);
3// [1, 2, 3] and [1, 2, 3, 4]
4// numbers is left alone
اما کد زیر نادرست است:
1nestedNumbers = [[1], [2]];
2numbersCopy = [];
3for (i = 0; i < nestedNumbers.length; i++) {
4 numbersCopy[i] = nestedNumbers[i];
5}
6numbersCopy[0].push(300);
7console.log(nestedNumbers, numbersCopy);
8// [[1, 300], [2]]
9// [[1, 300], [2]]
10// They've both been changed because they share references
3. روش حلقه ()While (کپی سطحی)
همان مطالبی که در مورد قبل در خصوص حلقه ()for گفتیم، در مورد این روش نیز صدق میکند:
1numbers = [1, 2, 3];
2numbersCopy = [];
3i = -1;
4while (++i < numbers.length) {
5 numbersCopy[i] = numbers[i];
6}
نکته: در این روش نیز اشیا/آرایهها به جای «با مقدار» به صورت «با ارجاع» انتساب مییابند.
کد زیر صحیح است:
1numbersCopy.push(4);
2console.log(numbers, numbersCopy);
3// [1, 2, 3] and [1, 2, 3, 4]
4// numbers is left alone
کد زیر صحیح نیست:
1nestedNumbers = [[1], [2]];
2numbersCopy = [];
3i = -1;
4while (++i < nestedNumbers.length) {
5 numbersCopy[i] = nestedNumbers[i];
6}
7numbersCopy[0].push(300);
8console.log(nestedNumbers, numbersCopy);
9// [[1, 300], [2]]
10// [[1, 300], [2]]
11// They've both been changed because they share references
4. روش Array.map (کپی سطحی)
امروزه و در روزگار مدرن با تابع map سر و کار داریم. ریشههای این تابع به ریاضیات بازمیگردد، چون «نگاشت» (map) به مفهوم تبدیل یک مجموعه به نوع دیگری از مجموعه، در عین حفظ ساختار گفته میشود. به زبان ساده Array.map هر بار یک آرایه با طول یکسان بازگشت میدهد.
برای دوبل کردن یک فهرست اعداد میتوان از map به همراه double استفاده کرد:
1numbers = [1, 2, 3];
2double = (x) => x * 2;
3numbers.map(double);
چه ربطی به Clone کردن دارد؟
از آنجا که مقاله ما در مورد کلون کردن است، برای ایجاد کپی تکراری از یک آرایه کافی است آن عنصر را در یک فراخوانی map بازگشت دهیم.
1numbers = [1, 2, 3];
2numbersCopy = numbers.map((x) => x);
اگر دوست دارید این توضیح را به زبان ریاضیاتی بشنوید، باید بگوییم که تابع زیر:
(x) => x
یک تابع همانی است که هر پارامتری به آن داده شود آن را بازگشت میدهد. بنابراین (map(identity موجب کلون شدن یک آرایه میشود.
1identity = (x) => x;
2numbers.map(identity);
3// [1, 2, 3]
نکته: در این روش نیز اشیا/آرایهها به جای روش «با مقدار» به صورت «با ارجاع» انتساب خواهند یافت.
5. روش Array.filter (کپی سطحی)
این تابع دقیقاً مانند map یک آرایه بازگشت میدهد؛ اما تضمینی وجود ندارد که آرایه بازگشتی طول مشابهی داشته باشد. برای نمونه در کد زیر اگر اعداد زوج را فیلتر کنیم چه اتفاقی میافتد؟
1[1، 2، 3].filter((x) => x% 2 === 0)
2// [2]
آرایه ورودی طولی برابر با 3 دارد؛ اما طول آرایه حاصل 1 است. اگر گزاره فیلتر شما همواره مقدار true بازگشت دهد، همیشه یک کپی تکراری از آرایه اصلی به دست میآورید:
1numbers = [1، 2، 3];
2numbersCopy = numbers.filter(() => true);
هر عنصر که تست را بگذراند، در خروجی آرایه بازگشت مییابد.
نکته: در این روش نیز اشیا/آرایهها به جای روش «با مقدار» به صورت «با ارجاع» انتساب مییابند.
6. روش Array.reduce (کپی سطحی)
با این که این روش برای کلون کردن یک آرایه چندان مناسب نیست؛ اما برای این که فهرستمان کامل باشد این گزینه را معرفی میکنیم. واقعیت این است که reduce قویتر از آن است که صرفاً برای کلون کردن یک آرایه استفاده شود:
1numbers = [1, 2, 3];
2numbersCopy = numbers.reduce((newArray, element) => {
3 newArray.push(element);
4 return newArray;
5}, []);
Reduce همچنان که روی یک لیست حلقهای تعریف میکند، یک مقدار اولیه را تبدیل میکند. در این روش مقدار اولیه یک آرایه خالی است که آن را با به تدریج با عناصر لیست پر میکنیم. این آرایه باید از تابع بازگشت پیدا کند تا در تکرار بعدی استفاده شود.
نکته: در این روش نیز اشیا/آرایهها به جای روش «با مقدار» به صورت «با ارجاع» انتساب مییابند.
7. روش Array.slice (کپی سطحی)
Slice یک کپی سطحی از یک آرایه بر مبنای اندیس آغازین/انتهایی ارائه شده بازمیگرداند. اگر 3 عنصر نخست را بخواهیم به صورت زیر عمل میکنیم:
1[1, 2, 3, 4, 5].slice(0, 3);
2// [1, 2, 3]
3// Starts at index 0, stops at index 3
اگر بخواهیم همه عناصر را داشته باشیم، باید هیچ پارامتری ندهیم:
1numbers = [1, 2, 3, 4, 5];
2numbersCopy = numbers.slice();
3// [1, 2, 3, 4, 5]
نکته: این روش یک کپی سطحی ایجاد میکند و از این رو در این روش نیز اشیا/آرایهها به جای روش «با مقدار» به صورت «با ارجاع» انتساب مییابند.
8. JSON.parse و JSON.stringify (کپی عمیق)
JSON.stringify یک شیء را به صورت یک رشته درمیآورد. JSON.parse یک رشته را به صورت یک شیء درمیآورد. ترکیب کردن آنها باعث میشود که یک شیء به یک رشته تبدیل شود. سپس این فرایند معکوس شود تا یک ساختار داده کاملاً جدید ایجاد شود.
نکته: این روش برای کپی کردن عمیق اشیا/آرایههای تودرتو به روش امن مناسب است.
1nestedNumbers = [[1], [2]];
2numbersCopy = JSON.parse(
3 JSON.stringify(nestedNumbers)
4);
5numbersCopy[0].push(300);
6console.log(nestedNumbers, numbersCopy);
7// [[1], [2]]
8// [[1, 300], [2]]
9// These two arrays are completely separate!
9. روش Array.concat (کپی سطحی)
concat آرایهها را با مقادیر و یا دیگر آرایهها ترکیب میکند.
1[1، 2، 3].concat(4); // [1، 2، 3، 4]
2[1، 2، 3].concat([4، 5]); // [1، 2، 3، 4، 5]
اگر هیچ چیز ارائه نشود یا یک آرایه خالی داده شود، یک کپی سطحی بازگشت مییابد:
1[1، 2، 3].concat(); // [1، 2، 3]
2[1، 2، 3].concat([]); // [1، 2، 3]
نکته: در این روش نیز اشیا/آرایهها به جای روش «با مقدار» به صورت «با ارجاع» انتساب مییابند.
10. روش Array.from (کپی سطحی)
این روش موجب میشود که هر شیء تکرارپذیر به یک آرایه تبدیل شود. با ارائه یک آرایه، یک کپی سطحی از آن بازگشت مییابد.
1numbers = [1, 2, 3];
2numbersCopy = Array.from(numbers)
3// [1, 2, 3]
نکته: در این روش نیز اشیا/آرایهها به جای روش «با مقدار» به صورت «با ارجاع» انتساب مییابند.
سخن پایانی
امیدواریم از مطالعه این مطلب لذت برده باشید. در این مقاله تلاش کردیم روشهای مختلف کلون کردن آرایه را در یک گام توضیح دهیم. با این وجود، اگر بخواهید از ترکیب متدها و تکنیکهای مختلف استفاده کنید، بدیهی است که روشهای بسیار بیشتری وجود دارد.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزشهای JavaScript (جاوا اسکریپت)
- آموزش JavaScript ES6 (جاوا اسکریپت)
- مجموعه آموزشهای برنامهنویسی
- جاوا اسکریپت چیست؟ — به زبان ساده
- متدهای ()map() ،reduce و ()filter در جاوا اسکریپت — به زبان ساده
- آموزش جاوا اسکریپت — مجموعه مقالات جامع وبلاگ فرادرس
==
عالی
مختصر و مفید