کپی کردن از یک لیست در لیست جدید
در جاوا اسکریپت کپی یک لیست در لیست دیگر به صورت پیش فرض به صورت ByRef انجام می شود یعنی در لیست دوم ارجاعی (reference) از لیست اول ذخیره می شود ، لذا اگر در محتویات لیست اول تغییر ایجاد گردد در لیست دوم نیز این تغییرات مشاهده می شود یا اگر در لیست دوم تغییری ایجاد شود در لیست اول نیز مشاهده می شود .
یادآوری : در جاوا اسکریپت، اصطلاح “لیست” به طور رسمی وجود ندارد و معمولاً زمانی که افراد در مورد لیستها صحبت میکنند، منظورشان آرایهها (Arrays) است. با این حال، تفاوتهای مفهومی بین لیستها و آرایهها در زبانهای برنامهنویسی دیگر وجود دارد.
در زبانهای دیگر، مانند Python و Java، لیستها ممکن است به نوع خاصی از دادهها اشاره کنند که ممکن است ویژگیهای متفاوتی نسبت به آرایهها داشته باشند. برای مثال، در Python لیستها پویا هستند و میتوانند انواع مختلفی از دادهها را در خود جای دهند. همچنین، لیستها در Python شامل تعداد زیادی متد برای مدیریت دادهها هستند.
let list = ['apple', 'banana', 'cherry', 'date']; let list2 = list(); // تغییری در لیست اصلی list[0] = 'avocado'; // مشاهده تغییر در لیست دوم console.log(list2); // ['avocado', 'banana', 'cherry', 'date'] // تغییری در لیست دوم list2[0] = 'apple'; // مشاهده تغییر در لیست اصلی console.log(list); // ['apple', 'banana', 'cherry', 'date']
ایجاد کپی مستقل از لیست ها
در بیش تر از مواقع نیاز هست که کپی دوم از کپی اصلی مستقل باشد و با تغییر در هر کدام از لیست ها ، در دیگری تغییری ایجاد نشود . برای این منظور شما باید از لیست اصلی یک کپی سطحی (Shallow Copy) یا عمیق (deep copy) در لیست دوم ایجاد کنید .
- کپی سطحی (Shallow Copy) برای آرایهها و اشیاء ساده که شامل دادههای پیچیده (مثل اشیاء یا آرایههای تو در تو) نیستند، کافی است.
- کپی عمیق (Deep Copy) برای آرایهها و اشیاء پیچیده که شامل دادههای تو در تو هستند، ضروری است تا مطمئن شویم تغییرات در کپی تاثیری بر نسخه اصلی ندارد.
به چهار روش می توانید یک کپی سطحی از لیست موجود ایجاد کنید .
۱- استفاده از slice()
متد slice()
بدون پارامترها یک کپی سطحی (shallow copy) از کل آرایه ایجاد میکند .
let list = ['apple', 'banana', 'cherry', 'date']; let list2 = list.slice(); // تغییری در لیست اصلی list[0] = 'avocado'; // عدم مشاهده تغییر در لیست دوم console.log(list2); // ['apple', 'banana', 'cherry', 'date']
متد slice ( به معنی برش ) جهت تکه تکه کردن آرایه نیز کاربرد دارد . متد slice دو ورودی دریافت می کند که اولی به ایندکس شروع و دومی به ایندکس پایان برش اشاره می کند . به عنوان مثال اگر مایلید یک برش از لیست اصلی از سطر اول تا سطر ۱۰ ایجاد نمایید کافیست متد slice را به صورت زیر فراخوانی نمایید .
let list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; // ایجاد برش ۱۰ سطر اول در لیست جدید let list2 = list.slice(0, 10); // مشاهده محتوای لیست دوم console.log(list2); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
۲- استفاده از concat()
متد concat()
نیز میتواند برای ایجاد یک کپی سطحی از آرایه استفاده شود .
let list = ['apple', 'banana', 'cherry', 'date']; let list2 = [ ].concat(list); // تغییری در لیست اصلی list[0] = 'avocado'; // عدم مشاهده تغییر در لیست دوم console.log(list2); // ['apple', 'banana', 'cherry', 'date']
۳- استفاده از spread operator
اسپرد اپراتور (...
) یکی از روشهای ساده و خوانا برای کپی کردن آرایهها است .
let list = ['apple', 'banana', 'cherry', 'date']; let list2 = [...list]; // تغییری در لیست اصلی list[0] = 'avocado'; // عدم مشاهده تغییر در لیست دوم console.log(list2); // ['apple', 'banana', 'cherry', 'date']
۴- استفاده از Array.from()
متد Array.from()
نیز میتواند برای کپی کردن آرایه استفاده شود .
let list = ['apple', 'banana', 'cherry', 'date']; let list2 = Array.from(list); // تغییری در لیست اصلی list[0] = 'avocado'; // عدم مشاهده تغییر در لیست دوم console.log(list2); // ['apple', 'banana', 'cherry', 'date']
همه این روشها یک کپی مستقل از آرایه اصلی ایجاد میکنند ، بنابراین تغییرات در آرایه اصلی تاثیری روی کپی نخواهد داشت .
تهیه کپی عمیق از یک لیست
اگر از یک لیست حاوی اطلاعات پیچیده کپی سطحی تهیه کنید ، اطلاعات ساده مستقل کپی می شود ولی اطلاعات پیچیده ( لیست های تودرتو و اشیاء ) ارجاعشان در لیست دوم کپی می شود با تغییر مقدارشان در هر دو لیست اثر می گذارند .
let originalArray = [1, 2, {a: 3}]; let shallowCopy = [...originalArray]; // تغییر در اطلاعات پیچیده کپی سطحی shallowCopy[2].a = 99; // تغییر در آرایه اصلی منعکس شده است console.log(originalArray); // [1, 2, {a: 99}] console.log(shallowCopy); // [1, 2, {a: 99}]
در اینجا، هر دو originalArray
و shallowCopy
به یک شیء {a: 3}
اشاره میکنند، بنابراین تغییرات در کپی سطحی در آرایه اصلی نیز منعکس میشود. برای رفع این مشکل حتما باید از لیست اصلی کپی عمیق تهیه کنید .
کپی عمیق (Deep Copy) به این معناست که یک کپی کامل و مستقل از آرایه یا شیء ایجاد میشود، به طوری که هیچ ارجاعی به مقادیر اصلی وجود نداشته باشد. این نوع کپی تضمین میکند که تغییرات در نسخه کپی تاثیری بر نسخه اصلی نخواهد داشت و بالعکس.
برای ایجاد کپی عمیق، میتوان از روشهای مختلفی استفاده کرد، مثل استفاده از کتابخانههای کمکی (مانند lodash
) یا تبدیل شیء به JSON و سپس دوباره به شیء :
let originalArray = [1, 2, {a: 3}]; let deepCopy = JSON.parse(JSON.stringify(originalArray)); deepCopy[2].a = 99; // تغییر در کپی عمیق console.log(originalArray); // [1, 2, {a: 3}] - تغییرات منعکس نشده است console.log(deepCopy); // [1, 2, {a: 99}]
در اینجا، deepCopy
یک کپی کامل و مستقل از originalArray
است، بنابراین تغییرات در deepCopy
تاثیری بر originalArray
ندارد.
منبع : Microsoft Colilot
متن سوال ها :
- وقتی یک لیست را به صورت مقابل تعریف می کنم :
let list = ['apple', 'banana', 'cherry', 'date']; let list2 = list;
حالا اگر تغییر در محتویات list اعمال کنم این تغییرات به صورت خودکار در list2 هم اعمال می شود که اصلا مطلوب نیست . به نظر می رسد مقدار list به صورت ByRef در list2 قرار گرفته است . به چه روشی مقدار list را به صورت ByVal در list2 کپی کنم ؟ - در توضیح روش کپی کردن مستقل آرایه ها صحبت از deep copy کردی و گفتی باید یک کپی عمیق از آرایه ایجاد کنیم ولی در سطرهای بعد که روش های کپی را توضیح دادی از عبارت کپی سطحی استفاده کردی . این موضوع من رو گیج کرده : بالاخره کپی عمیق یا کپی سطحی ؟ کدام صحیح است ؟