هيكلا البيانات الأكثر استخدامًا في JavaScript هما Object
و Array
.
تسمح لنا الكائنات بإنشاء كيان واحد يقوم بتخزين عناصر البيانات حسب المفتاح.
تسمح لنا المصفوفات بجمع عناصر البيانات في قائمة مرتبة.
ومع ذلك، عندما نمررها إلى دالة، قد لا نحتاج إليها كلها. قد تتطلب الوظيفة عناصر أو خصائص معينة فقط.
مهمة التدمير عبارة عن بناء جملة خاص يسمح لنا "بتفكيك" المصفوفات أو الكائنات في مجموعة من المتغيرات، حيث يكون ذلك أكثر ملاءمة في بعض الأحيان.
تعمل عملية التدمير أيضًا بشكل جيد مع الوظائف المعقدة التي تحتوي على الكثير من المعلمات والقيم الافتراضية وما إلى ذلك. قريبا سنرى ذلك.
فيما يلي مثال لكيفية تفكيك المصفوفة إلى متغيرات:
// لدينا مصفوفة بالاسم واللقب Let arr = ["جون"، "سميث"] // مهمة التدمير // يحدد الاسم الأول = arr[0] // واللقب = آر [1] دع [الاسم الأول، اللقب] = arr; تنبيه (الاسم الأول)؛ // جون تنبيه (اللقب)؛ // سميث
الآن يمكننا العمل مع المتغيرات بدلا من أعضاء المصفوفة.
يبدو رائعًا عند دمجه مع split
أو طرق إرجاع المصفوفات الأخرى:
دع [الاسم الأول، اللقب] = "جون سميث".split(' '); تنبيه (الاسم الأول)؛ // جون تنبيه (اللقب)؛ // سميث
كما ترون، بناء الجملة بسيط. هناك العديد من التفاصيل الغريبة بالرغم من ذلك. دعونا نرى المزيد من الأمثلة لفهمها بشكل أفضل.
"التدمير" لا يعني "المدمر".
يطلق عليه "مهمة التدمير"، لأنها "تدمر" عن طريق نسخ العناصر إلى متغيرات. ومع ذلك، لا يتم تعديل الصفيف نفسه.
إنها مجرد طريقة أقصر للكتابة:
// اسمحوا [الاسم الأول، اللقب] = arr؛ دع الاسم الأول = arr[0]; اسمحوا اللقب = arr[1];
تجاهل العناصر باستخدام الفواصل
يمكن أيضًا التخلص من العناصر غير المرغوب فيها من المصفوفة عبر فاصلة إضافية:
// العنصر الثاني غير مطلوب Let [firstName, , title] = ["يوليوس"، "قيصر"، "القنصل"، "الجمهورية الرومانية"]؛ تنبيه (العنوان)؛ // القنصل
في الكود أعلاه، يتم تخطي العنصر الثاني من المصفوفة، ويتم تعيين العنصر الثالث إلى title
، ويتم أيضًا تخطي بقية عناصر المصفوفة (حيث لا توجد متغيرات لها).
يعمل مع أي تكرار على الجانب الأيمن
…في الواقع، يمكننا استخدامه مع أي مصفوفات قابلة للتكرار، وليس فقط:
دع [أ، ب، ج] = "اي بي سي"؛ // ["أ"، "ب"، "ج"] Let [one, two, three] = new Set([1, 2, 3]);
ينجح ذلك، لأن مهمة التدمير داخليًا تعمل عن طريق التكرار على القيمة الصحيحة. إنه نوع من السكر النحوي للاستدعاء for..of
of فوق القيمة الموجودة على يمين =
وتعيين القيم.
تعيين إلى أي شيء على الجانب الأيسر
يمكننا استخدام أي "أشياء قابلة للتخصيص" على الجانب الأيسر.
على سبيل المثال، خاصية كائن:
دع المستخدم = {}؛ [user.name, user.surname] = "جون سميث".split(' '); تنبيه (اسم المستخدم) ؛ // جون تنبيه (user.surname)؛ // سميث
التكرار باستخدام .entries()
في الفصل السابق، رأينا طريقة Object.entries(obj).
يمكننا استخدامه مع التدمير للتكرار فوق مفاتيح وقيم الكائن:
السماح للمستخدم = { الاسم: "جون"، العمر: 30 }; // حلقة فوق المفاتيح والقيم لـ (دع [مفتاح، قيمة] لـ Object.entries(user)) { تنبيه(`${مفتاح}:${قيمة}`); // الاسم: جون، ثم العمر: 30 }
الكود المماثل Map
أبسط، لأنه قابل للتكرار:
السماح للمستخدم = خريطة جديدة ()؛ user.set("name", "John"); user.set("age", "30"); // تتكرر الخريطة كأزواج [مفتاح، قيمة]، وهي ملائمة جدًا للتدمير لـ (دع [مفتاح، قيمة] للمستخدم) { تنبيه(`${مفتاح}:${قيمة}`); // الاسم: جون، ثم العمر: 30 }
خدعة مبادلة المتغيرات
هناك خدعة معروفة لتبديل قيم متغيرين باستخدام مهمة التدمير:
دع الضيف = "جين"; دع المشرف = "بيت"؛ // لنتبادل القيم: make Guest=Pete, admin=Jane [ضيف، مشرف] = [مشرف، ضيف]؛ تنبيه(`${ضيف} ${admin}`); // بيت جين (تم التبديل بنجاح!)
نقوم هنا بإنشاء مصفوفة مؤقتة من متغيرين ثم نقوم بإتلافها على الفور بترتيب متبادل.
يمكننا تبديل أكثر من متغيرين بهذه الطريقة.
عادة، إذا كانت المصفوفة أطول من القائمة الموجودة على اليسار، فسيتم حذف العناصر "الإضافية".
على سبيل المثال، هنا يتم أخذ عنصرين فقط، ويتم تجاهل الباقي فقط:
Let [name1, name2] = ["يوليوس"، "قيصر"، "قنصل"، "الجمهورية الرومانية"]؛ تنبيه (اسم 1)؛ // يوليوس تنبيه (الاسم 2)؛ // قيصر // لم يتم تعيين العناصر الإضافية في أي مكان
إذا أردنا أيضًا جمع كل ما يلي – يمكننا إضافة معلمة أخرى تحصل على "الباقي" باستخدام ثلاث نقاط "..."
:
Let [name1, name2, ...rest] = ["يوليوس"، "قيصر"، "القنصل"، "الجمهورية الرومانية"]؛ // الباقي عبارة عن مصفوفة من العناصر، بدءًا من العنصر الثالث تنبيه(راحة[0]); // القنصل تنبيه(راحة[1]); // الجمهورية الرومانية تنبيه (الراحة. الطول)؛ // 2
قيمة rest
هي مصفوفة عناصر المصفوفة المتبقية.
يمكننا استخدام أي اسم متغير آخر بدلاً من rest
، فقط تأكد من أنه يحتوي على ثلاث نقاط قبله ويكون الأخير في مهمة التدمير.
Let [name1, name2, ...titles] = ["يوليوس"، "قيصر"، "القنصل"، "الجمهورية الرومانية"]؛ // الآن العناوين = ["القنصل"، "الجمهورية الرومانية"]
إذا كانت المصفوفة أقصر من قائمة المتغيرات الموجودة على اليسار، فلن تكون هناك أخطاء. تعتبر القيم الغائبة غير محددة:
دع [الاسم الأول، اللقب] = []؛ تنبيه (الاسم الأول)؛ // غير محدد تنبيه (اللقب)؛ // غير محدد
إذا أردنا قيمة "افتراضية" لتحل محل القيمة المفقودة، فيمكننا توفيرها باستخدام =
:
// القيم الافتراضية Let [name = "ضيف"، اللقب = "مجهول"] = ["يوليوس"]؛ تنبيه (الاسم)؛ // يوليوس (من المصفوفة) تنبيه (اللقب)؛ // مجهول (المستخدم افتراضيًا)
يمكن أن تكون القيم الافتراضية عبارة عن تعبيرات أكثر تعقيدًا أو حتى استدعاءات دالة. ويتم تقييمها فقط إذا لم يتم توفير القيمة.
على سبيل المثال، نستخدم هنا الدالة prompt
لاثنين من الإعدادات الافتراضية:
// يعمل فقط على المطالبة باللقب Let [name = موجه('name?'), اللقب = موجه('اللقب؟')] = ["يوليوس"]; تنبيه (الاسم)؛ // يوليوس (من المصفوفة) تنبيه (اللقب)؛ // مهما كان الموجه الذي يحصل عليه
يرجى ملاحظة: سيتم تشغيل prompt
فقط للقيمة المفقودة ( surname
).
تعمل مهمة التدمير أيضًا مع الكائنات.
بناء الجملة الأساسي هو:
دع {var1, var2} = {var1:…, var2:…}
يجب أن يكون لدينا كائن موجود على الجانب الأيمن، ونريد تقسيمه إلى متغيرات. يحتوي الجانب الأيسر على "نمط" يشبه الكائن للخصائص المقابلة. في أبسط الحالات، هذه قائمة بأسماء المتغيرات في {...}
.
على سبيل المثال:
دع الخيارات = { العنوان: "القائمة"، العرض: 100، الارتفاع: 200 }; دع {العنوان، العرض، الارتفاع} = الخيارات؛ تنبيه (العنوان)؛ // قائمة طعام تنبيه (العرض)؛ // 100 تنبيه (الارتفاع)؛ // 200
يتم تعيين الخصائص options.title
و options.width
و options.height
إلى المتغيرات المقابلة.
الترتيب لا يهم. هذا يعمل أيضًا:
// تم تغيير الترتيب في السماح {...} دع {الارتفاع، العرض، العنوان} = { العنوان: "القائمة"، الارتفاع: 200، العرض: 100 }
قد يكون النمط الموجود على الجانب الأيسر أكثر تعقيدًا ويحدد التعيين بين الخصائص والمتغيرات.
إذا أردنا تخصيص خاصية لمتغير باسم آخر، على سبيل المثال، جعل options.width
تدخل في المتغير المسمى w
، فيمكننا تعيين اسم المتغير باستخدام النقطتين:
دع الخيارات = { العنوان: "القائمة"، العرض: 100، الارتفاع: 200 }; // { sourceProperty: targetVariable } دع {العرض: العرض، الارتفاع: ح، العنوان} = الخيارات؛ // العرض -> ث // الارتفاع -> ح // العنوان -> العنوان تنبيه (العنوان)؛ // قائمة طعام تنبيه (ث)؛ // 100 تنبيه (ح)؛ // 200
يُظهر القولون "ماذا: يذهب إلى أين". في المثال أعلاه، ينتقل width
الخاصية إلى w
، وينتقل height
الخاصية إلى h
، ويتم تعيين title
لنفس الاسم.
بالنسبة للخصائص التي من المحتمل أن تكون مفقودة، يمكننا تعيين القيم الافتراضية باستخدام "="
، مثل هذا:
دع الخيارات = { العنوان: "القائمة" }; دع {العرض = 100، الارتفاع = 200، العنوان} = الخيارات؛ تنبيه (العنوان)؛ // قائمة طعام تنبيه (العرض)؛ // 100 تنبيه (الارتفاع)؛ // 200
تمامًا كما هو الحال مع المصفوفات أو معلمات الدوال، يمكن أن تكون القيم الافتراضية أي تعبيرات أو حتى استدعاءات دوال. وسيتم تقييمها إذا لم يتم توفير القيمة.
في الكود أدناه، يطلب prompt
width
، وليس title
:
دع الخيارات = { العنوان: "القائمة" }; Let {width = موجه("width؟"), title = موجه("title؟")} = options; تنبيه (العنوان)؛ // قائمة طعام تنبيه (العرض)؛ // (مهما كانت نتيجة المطالبة)
يمكننا أيضًا الجمع بين القولون والمساواة:
دع الخيارات = { العنوان: "القائمة" }; دع {العرض: ث = 100، الارتفاع: ح = 200، العنوان} = خيارات؛ تنبيه (العنوان)؛ // قائمة طعام تنبيه (ث)؛ // 100 تنبيه (ح)؛ // 200
إذا كان لدينا كائن معقد له العديد من الخصائص، فيمكننا استخراج ما نحتاجه فقط:
دع الخيارات = { العنوان: "القائمة"، العرض: 100، الارتفاع: 200 }; // استخراج العنوان كمتغير فقط دع {العنوان} = الخيارات؛ تنبيه (العنوان)؛ // قائمة طعام
ماذا لو كان الكائن يحتوي على خصائص أكثر مما لدينا من متغيرات؟ هل يمكننا أن نأخذ البعض ثم نخصص "الباقي" في مكان ما؟
يمكننا استخدام نمط الراحة، تمامًا كما فعلنا مع المصفوفات. إنه غير مدعوم من قبل بعض المتصفحات القديمة (IE، استخدم Babel لملئه)، ولكنه يعمل في المتصفحات الحديثة.
يبدو مثل هذا:
دع الخيارات = { العنوان: "القائمة"، الارتفاع: 200، العرض: 100 }; // العنوان = الخاصية المسماة title // بقية = كائن مع بقية الخصائص دع {العنوان، ...rest} = خيارات؛ // الآن title="Menu"، Rest={height: 200, width: 100} تنبيه (الراحة. الارتفاع)؛ // 200 تنبيه (الراحة. العرض)؛ // 100
مسكتك إذا لم يكن هناك let
في الأمثلة أعلاه، تم الإعلان عن المتغيرات بشكل صحيح في المهمة: let {…} = {…}
. بالطبع، يمكننا استخدام المتغيرات الموجودة أيضًا، دون let
. ولكن هناك صيد.
هذا لن ينجح:
اسمحوا العنوان، العرض، الارتفاع؛ // خطأ في هذا السطر {العنوان، العرض، الارتفاع} = {العنوان: "القائمة"، العرض: 200، الارتفاع: 100}؛
تكمن المشكلة في أن JavaScript تتعامل مع {...}
في تدفق التعليمات البرمجية الرئيسي (وليس داخل تعبير آخر) ككتلة تعليمات برمجية. يمكن استخدام كتل التعليمات البرمجية هذه لتجميع البيانات، مثل هذا:
{ // كتلة التعليمات البرمجية دع الرسالة = "مرحبا"؛ // ... تنبيه(رسالة); }
إذن هنا تفترض JavaScript أن لدينا كتلة تعليمات برمجية، ولهذا السبب يوجد خطأ. نريد التدمير بدلا من ذلك.
لإظهار أن جافا سكريبت ليست كتلة تعليمات برمجية، يمكننا وضع التعبير بين قوسين (...)
:
اسمحوا العنوان، العرض، الارتفاع؛ // حسنا الآن ({العنوان، العرض، الارتفاع} = {العنوان: "القائمة"، العرض: 200، الارتفاع: 100}); تنبيه (العنوان)؛ // قائمة طعام
إذا كان كائن أو مصفوفة تحتوي على كائنات ومصفوفات متداخلة أخرى، فيمكننا استخدام أنماط الجانب الأيسر الأكثر تعقيدًا لاستخراج أجزاء أعمق.
في الكود أدناه تحتوي options
على كائن آخر في size
الخاصية ومصفوفة في items
الخاصية. النمط الموجود على الجانب الأيسر من المهمة له نفس البنية لاستخراج القيم منها:
دع الخيارات = { مقاس: { العرض: 100، الارتفاع: 200 }, العناصر: ["كيك"، "دونات"]، اضافية: صحيح }; // مهمة التدمير مقسمة إلى عدة أسطر من أجل الوضوح يترك { الحجم: {// ضع الحجم هنا عرض، ارتفاع }, العناصر: [item1, item2], // قم بتعيين العناصر هنا العنوان = "القائمة" // غير موجود في الكائن (يتم استخدام القيمة الافتراضية) } = الخيارات؛ تنبيه (العنوان)؛ // قائمة طعام تنبيه (العرض)؛ // 100 تنبيه (الارتفاع)؛ // 200 تنبيه (البند 1)؛ // كيك تنبيه (البند 2)؛ // كعكة محلاة
يتم تعيين جميع خصائص كائن options
، باستثناء extra
الغائبة في الجزء الأيسر، إلى المتغيرات المقابلة:
أخيرًا، لدينا width
و height
و item1
و item2
و title
من القيمة الافتراضية.
لاحظ أنه لا توجد متغيرات size
items
، لأننا نأخذ محتواها بدلاً من ذلك.
في بعض الأحيان تحتوي الدالة على العديد من المعلمات، معظمها اختيارية. وهذا ينطبق بشكل خاص على واجهات المستخدم. تخيل وظيفة تقوم بإنشاء قائمة. قد يكون لها عرض وارتفاع وعنوان وقائمة عناصر وما إلى ذلك.
إليك طريقة سيئة لكتابة مثل هذه الوظيفة:
وظيفة showMenu(العنوان = "بدون عنوان"، العرض = 200، الارتفاع = 100، العناصر = []) { // ... }
في الحياة الواقعية، المشكلة هي كيفية تذكر ترتيب الحجج. عادة، تحاول IDEs مساعدتنا، خاصة إذا كانت التعليمات البرمجية موثقة جيدًا، ولكن لا تزال هناك مشكلة أخرى وهي كيفية استدعاء دالة عندما تكون معظم المعلمات جيدة بشكل افتراضي.
مثله؟
// غير محدد حيث تكون القيم الافتراضية جيدة showMenu("قائمتي"، غير محدد، غير محدد، ["Item1"، "Item2"])
هذا قبيح. ويصبح غير قابل للقراءة عندما نتعامل مع المزيد من المعلمات.
التدمير يأتي للإنقاذ!
يمكننا تمرير المعلمات ككائن، وتقوم الدالة بتفكيكها على الفور إلى متغيرات:
// نقوم بتمرير الكائن إلى الوظيفة دع الخيارات = { العنوان: "قائمتي"، العناصر: ["العنصر 1"، "العنصر 2"] }; // ...ويقوم بتوسيعه على الفور إلى المتغيرات وظيفة showMenu({title = "Untitled"، العرض = 200، الارتفاع = 100، العناصر = []}) { // العنوان، العناصر – مأخوذة من الخيارات، // العرض والارتفاع - الإعدادات الافتراضية المستخدمة تنبيه( `${title} ${width} ${height}` ); // قائمتي 200 100 تنبيه (العناصر)؛ // العنصر 1، العنصر 2 } showMenu(options);
يمكننا أيضًا استخدام عمليات تدمير أكثر تعقيدًا مع الكائنات المتداخلة وتعيينات النقطتين:
دع الخيارات = { العنوان: "قائمتي"، العناصر: ["العنصر 1"، "العنصر 2"] }; وظيفة عرض القائمة({ العنوان = "بدون عنوان"، العرض: ث = 100، // العرض يذهب إلى ث الارتفاع: h = 200، // الارتفاع يذهب إلى h العناصر: [item1, item2] // العنصر الأول يذهب إلى العنصر 1، والثاني إلى العنصر 2 }) { تنبيه( `${title} ${w} ${h}` ); // قائمتي 100 200 تنبيه(البند1); // العنصر1 تنبيه(البند2); // العنصر2 } showMenu(options);
بناء الجملة الكامل هو نفسه بالنسبة لمهمة التدمير:
وظيفة({ incomingProperty: varName = defaultValue ... })
بعد ذلك، بالنسبة لكائن المعلمات، سيكون هناك متغير varName
للخاصية incomingProperty
، مع القيمة الافتراضية defaultValue
.
يرجى ملاحظة أن مثل هذا التدمير يفترض أن showMenu()
لديه وسيطة. إذا أردنا جميع القيم بشكل افتراضي، فيجب علينا تحديد كائن فارغ:
showMenu({}); // حسنًا، جميع القيم افتراضية showMenu(); // هذا من شأنه أن يعطي خطأ
يمكننا إصلاح ذلك عن طريق جعل {}
القيمة الافتراضية لكائن المعلمات بالكامل:
وظيفة showMenu({ title = "القائمة"، العرض = 100، الارتفاع = 200 } = {}) { تنبيه( `${title} ${width} ${height}` ); } showMenu(); // القائمة 100200
في الكود أعلاه، كائن الوسيطات بأكمله هو {}
افتراضيًا، لذلك هناك دائمًا شيء يجب تدميره.
تسمح مهمة التدمير بتعيين كائن أو مصفوفة على العديد من المتغيرات على الفور.
بناء جملة الكائن الكامل:
Let {prop : varName = defaultValue, ...rest} = object
هذا يعني أن prop
الخاصية يجب أن تنتقل إلى المتغير varName
، وفي حالة عدم وجود مثل هذه الخاصية، فيجب استخدام القيمة default
.
يتم نسخ خصائص الكائن التي ليس لها تعيين إلى الكائن rest
.
بناء جملة المصفوفة الكاملة:
Let [item1 = defaultValue, item2, ...rest] = array
العنصر الأول يذهب إلى item1
; يذهب الثاني إلى item2
، وكل الباقي يجعل المصفوفة rest
.
من الممكن استخراج البيانات من المصفوفات/الكائنات المتداخلة، لذلك يجب أن يكون للجانب الأيسر نفس بنية الجانب الأيمن.
الأهمية: 5
لدينا كائن:
السماح للمستخدم = { الاسم: "جون"، سنوات: 30 };
اكتب مهمة التدمير التي تقرأ:
خاصية name
في name
المتغير.
خاصية years
في متغير age
.
خاصية isAdmin
في المتغير isAdmin
(خطأ، إذا لم يكن هناك مثل هذه الخاصية)
فيما يلي مثال على القيم بعد مهمتك:
Let user = { name: "John"، السنوات: 30 }; // الكود الخاص بك على الجانب الأيسر: // ... = المستخدم تنبيه (الاسم)؛ // جون تنبيه (العمر)؛ // 30 تنبيه(isAdmin); // خطأ شنيع
السماح للمستخدم = { الاسم: "جون"، سنوات: 30 }; دع {الاسم، السنوات: العمر، isAdmin = false} = مستخدم؛ تنبيه (الاسم)؛ // جون تنبيه (العمر)؛ // 30 تنبيه(isAdmin); // خطأ شنيع
الأهمية: 5
هناك كائن salaries
:
دع الرواتب = { "جون": 100، "بيت": 300، "مريم": 250 };
قم بإنشاء الدالة topSalary(salaries)
التي تُرجع اسم الشخص الذي يتقاضى أعلى أجر.
إذا كانت salaries
فارغة فيجب أن تعود null
.
إذا كان هناك العديد من الأشخاص ذوي الأجور المرتفعة، قم بإرجاع أي منهم.
ملاحظة: استخدم Object.entries
والتدمير للتكرار على أزواج المفتاح/القيمة.
افتح صندوق الرمل مع الاختبارات.
وظيفة أعلى الراتب (الرواتب) { دع maxSalary = 0; دع maxName = null; لـ(const [الاسم، الراتب] لـ Object.entries(salaries)) { إذا (الحد الأقصى للرواتب <الراتب) { maxSalary = الراتب؛ maxName = name; } } إرجاع الاسم الأقصى؛ }
افتح الحل بالاختبارات في وضع الحماية.