ویرگول
ورودثبت نام
مصطفی رستگار
مصطفی رستگاربرنامه نویس کامپیوتر و ازین جور مسخره بازی ها!
مصطفی رستگار
مصطفی رستگار
خواندن ۳ دقیقه·۴ ماه پیش

14- Deep Copy vs Shallow Copy (مشکل structuredClone و JSON.stringify)

۱. تعریف اولیه (برای شروع صحبت):

«در جاوااسکریپت، وقتی از آبجکت‌ها یا آرایه‌ها کپی می‌گیریم، باید به دو نوع کپی دقت کنیم: Shallow Copy و Deep Copy. تفاوت اصلی در این است که یک کپی چقدر از آبجکت اصلی مستقل می‌شود.»

۲. تفاوت مفهومی (با مثال ساده):

«در Shallow Copy یا کپی سطحی، فقط خود آبجکت اصلی در یک آدرس جدید ساخته می‌شود، اما اگر داخل آبجکت، آبجکت‌های تو در تو (یا آرایه) داشته باشیم، آن‌ها هنوز به همان حافظهٔ قبلی اشاره می‌کنند. یعنی اگر مقدار یک آبجکت تو در تو را تغییر دهم، آن تغییر در هر دو نسخه (اصلی و کپی) دیده می‌شود.»

«در Deep Copy یا کپی عمیق، همه‌چیز از اول و به‌صورت کامل کپی می‌شود. دیگر هیچ اشاره‌ای به آبجکت اصلی نداریم و تغییر در کپی، روی اصل تأثیر نمی‌گذارد و برعکس.»

۳. روش‌های معمول (با ذکر محدودیت‌ها):

«برای کپی سطحی معمولاً از اسپرید (...) یا Object.assign استفاده می‌کنیم.»

«برای کپی عمیق، خیلی‌ها از دو روش استفاده می‌کنند: یکی JSON.stringify به همراه JSON.parse و دیگری تابع structuredClone که جدیدتر است.»

«اما نکته‌ی مهم اینجاست که هیچ‌کدام از این دو روش کامل نیستند و محدودیت‌های مشخصی دارند.»

۴. مشکل اصلی (همان سوال کلیدی مصاحبه):

«مشکل اول با JSON.stringify/parse: این روش فقط داده‌هایی را پشتیبانی می‌کند که فرمت JSON داشته باشند. یعنی توابع، undefined، Symbol، تاریخ (Date) و بعضی از آبجکت‌های خاص مثل Map و Set را از دست می‌دهد یا تبدیل اشتباهی انجام می‌دهد. مثلاً تاریخ را به رشته تبدیل می‌کند و دیگر یک شیء تاریخ نمی‌ماند.»

«مشکل دوم با structuredClone: این تابع خیلی بهتر است و از تاریخ، Map، Set و حتی داده‌های باینری پشتیبانی می‌کند. اما باز هم کامل نیست؛ مثلاً توابع را نمی‌تواند کپی کند و اگر آبجکت شما شامل توابع یا Symbol باشد، خطا می‌دهد. همچنین بعضی از آبجکت‌های خاص مثل Error یا Element (DOM) را هم پشتیبانی نمی‌کند.»

۵. جمع‌بندی نهایی (برای نشان دادن تسلط):

«پس به‌طور خلاصه، اگر داده‌ی ما فقط شامل اشیاء ساده و JSON-friendly است، structuredClone انتخاب خوبی است. اما اگر داده شامل توابع، سمبل‌ها، یا آبجکت‌های غیرقابل‌سریال‌سازی است، باید از کتابخانه‌های تخصصی مثل Lodash با متد cloneDeep استفاده کنیم، یا خودمان کپی‌عمیق را به‌صورت بازگشتی پیاده‌سازی کنیم.»

«نکته‌ی کلیدی که باید به خاطر داشته باشیم این است که هیچ روش داخلی در جاوااسکریپت برای کپی عمیق ۱۰۰٪ کامل وجود ندارد و انتخاب روش به نوع داده‌ی ما بستگی دارد.»


اگر سوال مکمل بپرسند (نکات اضافه برای جایزه گرفتن):

  • کاربرد structuredClone: در Web Workers یا برای ذخیره‌سازی داده‌ها خیلی مفید است چون از ساختارهای جدید پشتیبانی می‌کند.

  • تفاوت structuredClone با JSON: دومی سریع‌تر است ولی اولی امن‌تر و کامل‌تر برای داده‌های مدرن جاوااسکریپت.

  • راه‌حل نهایی: اگر کتابخانه‌ای مثل Lodash مجاز نیست، می‌توانیم یک تابع بازگشتی بنویسیم که نوع داده را چک کند و برای هر نوع (آرایه، آبجکت، Map، Set و ...) کپی مخصوص خودش را انجام دهد.


اگر بخواهی این متن را با لحن خودت و با مثال عملی کوتاه هم همراه کنی، خیلی تأثیرگذارتر خواهد شد. مثلاً:

«مثلاً اگر من یک آبجکت داشته باشم که داخلش یک تاریخ (new Date()) باشد و از JSON.stringify استفاده کنم، آن تاریخ به یک رشته تبدیل می‌شود و وقتی دوباره پارس می‌کنم، دیگر یک شیء تاریخ نیست و متدهای getMonth یا getFullYear روی آن کار نمی‌کند.»

deep copyshallow copyمصاحبه فنی
۱
۰
مصطفی رستگار
مصطفی رستگار
برنامه نویس کامپیوتر و ازین جور مسخره بازی ها!
شاید از این پست‌ها خوشتان بیاید