نسخت object بـ JSON وخرب التاريخ؟ استعمل structuredClone

الـ structuredClone بيعمل نسخة عميقة بتحافظ على Date وMap وSet والمراجع الدايرية، يلي JSON.parse(JSON.stringify()) بيخرّبها. بس الـ functions والـ DOM ما بتنسخ.

نُشر في 3 دقائق قراءة#تطوير الويب#أدوات المطورين

بدك تعدّل على نسخة من طلب بالسلة بلا ما تلمس الأصل، فبتكتب السطر المعروف JSON.parse(JSON.stringify(order)). النسخة بتطلع، بس تاريخ الطلب صار نص، والـ Set تبع الوسوم صار object فاضي. بآخر هالمقال رح تعرف ليش بيصير هيك، وكيف تنسخ بـ structuredClone، وشو الأشياء يلي لازم تنسخها بإيدك.

شو هو structuredClone؟

الـ structuredClone دالة جاهزة بـ JavaScript بتعمل نسخة عميقة لأي قيمة، يعني بتنسخ كل طبقة جوّا الـ object، مش بس أول طبقة.

حسب صفحة structuredClone على MDN، الدالة بتشتغل بخوارزمية اسمها structured clone algorithm، وشكلها structuredClone(value) أو structuredClone(value, options). وإذا في جزء من القيمة ما بينسخ، بترمي خطأ DataCloneError. الصفحة نفسها بتقول إنها متاحة عبر المتصفحات من آذار 2022.

شو بيخرب لما تنسخ بـ JSON؟

النسخ بـ JSON.parse(JSON.stringify()) بيخرّب كل قيمة مش من أنواع JSON: التاريخ بيصير نص، والـ Map والـ Set بيصيروا objects فاضية.

صفحة JSON.stringify على MDN بتشرح كل حالة:

  • الـ Date عنده toJSON() بيرجّع نفس toISOString()، يعني نص. وبعد JSON.parse بيضل نص، مش تاريخ.

  • بيزور الخصائص الخاصة القابلة للعدّ بس، فالـ Map والـ Set بيصيروا "{}".

  • القيم undefined والـ functions والـ Symbol بتنشال إذا كانت جوّا object، وبتصير null إذا كانت جوّا array.

  • قيمة BigInt أو مرجع دايري (object بيأشّر على حاله) بيرمي TypeError.

const order = { createdAt: new Date(), tags: new Set(["paid"]) };
const viaJson = JSON.parse(JSON.stringify(order));

typeof viaJson.createdAt; // "string"
viaJson.tags;             // {}

بهالمثال ما في ولا خطأ وقت النسخ، فالغلط ما بيبيّن إلا لما الكود يتعامل مع createdAt كأنو لسا تاريخ.

كيف تنسخ object بـ structuredClone؟

بتنسخ object بـ structuredClone لما تمرّقه للدالة، وبترجعلك نسخة جديدة بنفس القيم وبنفس الأنواع.

const order = { createdAt: new Date(), tags: new Set(["paid"]) };
order.self = order;

const copy = structuredClone(order);

copy !== order;        // true
copy.self === copy;    // true

السطرين الأخيرين من نفس فكرة مثال MDN: النسخة مش نفس الـ object، والمرجع الدايري بيضل بالنسخة وبيأشّر عليها هي. والـ Date والـ Map والـ Set كلهن من الأنواع يلي الخوارزمية بتنسخها، فبيطلعوا بالنسخة بأنواعهن.

شو الأشياء يلي ما بينسخها structuredClone؟

الـ structuredClone ما بينسخ الـ functions ولا عناصر الـ DOM، وما بينقل الـ prototype ولا الـ getters والـ setters.

صفحة الخوارزمية على MDN بتعدّهن:

الشي

شو بيصير

Function

بيرمي DataCloneError

عنصر DOM

بيرمي DataCloneError

الـ getters والـ setters ووصف الخصائص

ما بينسخوا: خاصية readonly بتصير قابلة للتعديل بالنسخة

الـ prototype chain

ما بيمشي عليها ولا بينسخها

الحقول الخاصة بالـ class (#field)

ما بتنسخ

lastIndex تبع RegExp

ما بيضل

ونفس الصفحة بتقول إنو الـ objects يلي بتنسخ هي الـ objects العادية بس (متل يلي بتعملها بـ {}). فإذا عندك كائنات من class فيها methods أو حقول خاصة، لا تتّكل على structuredClone لهي: اعمل method نسخ بالكلاس نفسه، أو انسخ البيانات العادية بس وابني الكائن من جديد.

إمتى بتستعمل خيار transfer؟

بتستعمل خيار transfer لما عندك buffer كبير وبدك تنقله للنسخة بدل ما تنسخه، والأصل بيفضى بعدها.

صفحة MDN بتقول إنو الكائنات يلي بتحطها بـ transfer بتنتقل بدل ما تنسخ، وبمثالها byteLength تبع الأصل بيصير 0 بعد النقل:

const bytes = new Uint8Array([1, 2, 3, 4]);
const moved = structuredClone(bytes, { transfer: [bytes.buffer] });

bytes.byteLength; // 0

يعني بعد النقل ما تستعمل الأصل. هاد مفيد لما الملف أو الصورة كبار وما بدك تدفع تمن نسختين بالذاكرة.

من وين تبلّش هلق؟

دوّر بمشروعك على JSON.parse(JSON.stringify( وشوف شو بيمرق فيها: إذا في تواريخ أو Map أو Set، بدّلها بـ structuredClone، وإذا في functions أو كائنات class، قرّر شو بدك تنسخ بالزبط.

وإذا عم تشتغل بـ TypeScript، شوف شو تغيّر بآخر نسخة تجريبية منه. ومقالات تانية من نفس النوع بـ موضوع تطوير الويب، وإذا بعدك بأول الطريق، خارطة طريق المبرمج مجانية.

وين آخر مكان بكودك نسخت فيه object بـ JSON، وشو كان جوّاه؟

أسئلة شائعة

هل structuredClone بينسخ كائن من class؟

مش متل ما بتتوقع. الخوارزمية بتنسخ الـ objects العادية بس، وما بتمشي على الـ prototype chain، والحقول الخاصة بالـ class ما بتنسخ. انسخ البيانات العادية وابني الكائن من جديد.

هل structuredClone شغّال بكل المتصفحات؟

إي، بالمتصفحات الحالية. صفحة MDN بتقول إنو متاح عبر المتصفحات من آذار 2022، ومعلّم إنو متوفر على نطاق واسع.

شو بيصير إذا الـ object فيه function؟

الـ structuredClone بيرمي خطأ DataCloneError، والنسخة ما بتنعمل. شيل الـ function قبل النسخ، أو انسخ البيانات بس.

شارك المقال

نسخة Markdown

مقالات أخرى