تفاوت کپی سطحی و کپی عمیق رو میدونی ؟
تفاوت کپی سطحی و کپی عمیق رو میدونی ؟
چند بار تا حالا سعی کردی توی جاوااسکریپت یه آبجکت رو کپی کنی ولی نتیجه دقیقاً اون چیزی نبوده که انتظار داشتی؟
توی این قسمت قراره مفاهیم پایهای پشت کپی کردن رو توضیح بدیم تا همیشه از روش درست استفاده کنی و به مشکل نخوری.
امروز میخواهیم تفاوت بین دو نوع کپی در جاوااسکریپت یعنی shallow copy و deep copy رو بررسی کنیم.
این دو موضوع بسیار مهم هستند، چون وقتی با دادههای پیچیده و چند لایه مثل آرایهها یا آبجکتها کار میکنید، خیلی اهمیت پیدا میکنه که بدونید کدوم نوع کپی انجام میشه و چطور ممکنه دادهها تغییر کنند.
کپی سطحی یا (shallow copy) :
«کپی سطحی» یا shallow copy به این معنیه که فقط یک کپی از سطوح بالا ایجاد میکنه، اما اگر آرایه یا آبجکت شامل مقادیر تو در تو باشه (مثل آبجکتهای درون آبجکت یا آرایههای توی آبجکت)، فقط مرجع اونها کپی میشه نه مقدار واقعی .
برای ایجاد یک کپی سطحی در جاوااسکریپت، میتونیم از اپراتور spread (…) یا Object.assign() استفاده کنیم.
const obj = { name: 'Version 1', info: { version: ۱ } };
const shallowCopy1 = { ...obj };
const shallowCopy2 = Object.assign({}, obj);
shallowCopy1.name = 'Version 2';
shallowCopy1.info.version = ۲;
shallowCopy2.name = 'Version 2';
shallowCopy2.info.version = ۲;
console.log(obj); // { name: 'Version 1', info: { version: 2 } }
console.log(shallowCopy1); // { name: 'Version 2', info: { version: 2 } }
console.log(shallowCopy2); // { name: 'Version 2', info: { version: 2 } }
همونطور که در این کد میبینی:
بعد از بهروزرسانی یک پراپرتی در سطح اول آبجکتهای کپیشده، پراپرتی اصلی تغییر نمیکنه.
اما وقتی یک پراپرتی در سطحهای عمیقتر بهروزرسانی میشه، پراپرتی اصلی هم تغییر میکنه. این اتفاق به این دلیله که در این حالت، سطحهای عمیقتر رفرنس میشن، نه اینکه کپی بشن.
حالا deep copy یا کپی عمیق:
«کپی عمیق» یا deep copy به این معناست که تمام مقادیر آبجکت یا آرایه، حتی مقادیر تو در تو، به طور کامل کپی میشن. یعنی هیچ مرجعی به آبجکت اصلی باقی نمیمونه.
روشهای ایجاد deep copy:
استفاده از JSON:
این یکی از سادهترین روشهاست، اما یه مشکل داره: JSON.stringify و JSON.parse فقط با آبجکتهای ساده کار میکنن و نمیتونن توابع، undefined یا برخی از پراپرتی های پیچیدهتر جاوااسکریپت رو کپی کنن.
let originalObj = { name: "Ali", skills: ["JS", "React"] };
let deepCopyObj = JSON.parse(JSON.stringify(originalObj));
deepCopyObj.skills[۰] = "Python";
console.log(originalObj.skills[۰]); // JS - اینجا دیگه مقدار اصلی تغییر نکرده!
در این روش، deepCopyObj یه کپی کامل از originalObj ایجاد میکنه و حتی آرایهی skills هم به طور مستقل کپی میشه.
استفاده از کتابخانهها:
برای پروژههای بزرگتر میتونید از کتابخانههایی مثل Lodash استفاده کنید که توابع آماده برای کپی عمیق ارائه میده.
مثال با Lodash:
let originalObj = { name: "Ali", skills: ["JS", "React"] };
let deepCopyObj = _.cloneDeep(originalObj);
deepCopyObj.skills[۰] = "Python";
console.log(originalObj.skills[۰]); // JS - تغییر نکرده
میتونی به سایت رسمی Lodash مراجعه کنی برای دیدن مستنداتش.
عملکرد
به دلایل واضح، کپیهای سطحی خیلی سریعتر از کپیهای عمیق انجام میشن. اما این به این معنی نیست که همیشه باید از کپی سطحی استفاده کنی، چون گاهی اوقات به کپی از آبجکتهای تو در تو هم نیاز داری. پس کدوم گزینه رو باید انتخاب کنم؟
- اگه عمق آبجکتت برابر با یکه، از کپی سطحی استفاده کن.
- اگه عمق آبجکتت بیشتر از یکه، کپی عمیق بهتره.
حتماً از وب اپلیکیشن DevDocs استفاده کن چون میتونی همه مستندات رو داشته باشی که آموزشش رو تهیه کردم که میتونی از این لینک ببینیش.