ملاحظة مهمة: هذه إضافة حديثة للغة، لذا قد تحتاج المتصفحات القديمة لترقيع هذا النقص.
التسلسل الاختياري .?
هو طريقة مقاومة للأخطاء للوصول إلى خصائص الكائن المتداخلة، حتى إذا كانت الخاصية الوسيطة غير موجودة.
المشكلة
إذا كنت قد بدأت للتو في قراءة هذه السلسلة التعليمية وتتعلم جافاسكربت، فلربما لم تواجه هذه المشكلة بعد، لكنها شائعة جدًا.
فمثلًا، يمتلك بعض من المستخدمين لدينا يمتلكون عناوين، لكن هنالك قليل منهم لم يقدمها. لذا لا يمكننا قراءة user.address.street
بأمان. هكذا:
let user = {}; // تحدث للمستخدم user في حالة كان ليس لديه عنوان alert(user.address.street); // خطأ!
أو عند تطويرنا لموقع وِب، ونرغب في الحصول على معلومات حول عنصر ما في الصفحة، لكنه قد لا يكون موجودًا:
// إذا كان نتيجة querySelector(...) فارغًا let html = document.querySelector('.my-element').innerHTML;
قبل ظهور "?." في اللغة، كان يستخدم المعامل &&
للتغلب على المشكلة.
فمثلًا:
let user = {}; // إذا كان user لا يملك عنوان alert( user && user.address && user.address.street ); // undefined (أي ليس خطأً)
وكونها تتطلب كتابة طويلة للتأكد من وجود جميع المكونات، لذلك كان استخدامها مرهقًا.
تسلسل اختياري
التسلسل الاختياري "?." يوقف التقييم ويعيد غير معرّف undefined
إذا كان الجزء قبل "?." غير معرّف undefined
أو فارغ null
.
**للإيجاز سنفترض في هذه المقالة أن شيئًا ما "موجود" إذا لم تكن القيمة "فارغة" null
أو غير معرّفة undefined
. **
إليك الطريقة الآمنة للوصول إلى user.address.street
:
let user = {}; // إذا كان user لا يملك عنوان alert( user?.address?.street ); // undefined (ليس خطأً)
إن قراءة العنوان باستخدام هذه الطريقة user?.address
ستعمل حتى ولو كان الكائن user
غير موجود:
let user = null; alert( user?.address ); // undefined alert( user?.address.street ); // undefined
الرجاء ملاحظة أن: صياغة جملة .?
تجعل القيمة الموجودة قبلها اختيارية، ولكن ليس القيمة الّتي تأتي بعدها.
في المثال أعلاه، تسمح التعليمة "user?." للكائن user
فقط بأن يكون غير معرف أو فارغ "null/undefined". من ناحية أخرى، إذا كان الكائن user
موجودًا، فيجب أن يحتوي على خاصية user.address
، وإلا فإن user?.address.street
ستُعطي خطأ في النقطة الثانية.
ملاحظة: لا تفرط في استخدام التسلسل الاختياري. يجب أن نستخدم .?
فقط في حالة عدم وجود شيئ ما.
فمثلًا، بحسب منطق الشيفرة خاصتنا يجب أن يكون الكائن user
موجودًا، ولكن الخاصية address
اختيارية، بهذه الحالة سيكون user?.address.street
أفضل. لذلك، إذا حدث أن كان الكائن user
غير معرف بسبب خطأ ما، فسنُعرف عنه ونصلحه. خلاف ذلك، يمكن إسكات أخطاء الترميز عندما لا يكون ذلك مناسبًا، ويصبح تصحيحها أكثر صعوبة.
ملاحظة: يجب التصريح عن المتغير الموجود قبل .?
إذا لم يكن هناك متغير user
على الإطلاق، فإن التعليمة user?.anything
ستؤدي حتمًا إلى حدوث خطأ:
// ReferenceError: إن المستخدم user غير معرًف user?.address;
يجب أن يكون هناك تعريف واضح للمتغير let / const / var user
. لأن التسلسل الاختياري يعمل فقط للمتغيرات المصرح عنها.
اختيار الطريق الأقصر
كما قلنا سابقًا، ستوقف .?
فورًا (أي سيحدث قصر في الدارة) إذا لم يكن الجزء الأيسر موجودًا.
لذلك، إذا كان هناك أي استدعاءات دوالّ أخرى أو آثار جانبية، فلن تحدث:
let user = null; let x = 0; user?.sayHi(x++); // لا يحدث شيئ alert(x); // 0, لم تزداد القيمة
حالات أخرى ()?. و []?.
إن التسلسل الاختياري .?
ليس مُعامل، ولكنه طريقة معينة لصياغة تعليمة، يعمل أيضًا مع الدوالّ والأقواس المربعة.
فمثلًا، تُستخدم ().?
لاستدعاء دالّة قد لا تكون موجودة.
نلاحظ في الشيفرة أدناه، أنه لدى بعض مستخدمينا التابع admin
والبعض ليس لديه:
let user1 = { admin() { alert("I am admin"); } } let user2 = {}; user1.admin?.(); // I am admin user2.admin?.();
هنا، في كلا السطرين، نستخدم النقطة .
أولًا للحصول على خاصية admin
، لأن كائن المستخدم user
يجب أن يكون موجودًا، لذا فهو آمن للقراءة منه. ثم يتحقق ().?
من الجزء الأيسر: إذا كانت دالّة المسؤول موجودة، فستنفذ (على الكائن user1
). وبخلاف ذلك (بالنسبة للكائن user2
) يتوقف التقييم الشيفرة بدون أخطاء.
تعمل الصياغة [].?
أيضًا، إذا أردنا استخدام الأقواس []
للوصول إلى الخصائص بدلًا من النقطة .
. على غرار الحالات السابقة، فإنه يسمح بقراءة خاصية بأمان من كائن قد لا يكون موجودًا.
let user1 = { firstName: "John" }; let user2 = null; // Imagine, we couldn't authorize the user let key = "firstName"; alert( user1?.[key] ); // John alert( user2?.[key] ); // undefined alert( user1?.[key]?.something?.not?.existing); // undefined
كما يمكننا استخدام .?
مع delete
:
delete user?.name; // احذف المستخدم user.name إذا كان موجودًا
ملاحظة: يمكننا استخدام .?
للقراءة الآمنة والحذف، ولكن ليس الكتابة
التسلسل الاختياري .?
ليس له أي فائدة في الجانب الأيسر من المهمة:
// فكرة الشيفرة أدناه أن تكتب قيمة user.name إذا لم تكن موجودة user?.name = "John"; // خطأ لن تعمل الشيفرة // لأن الإسناد بين undefined = "John"
الخلاصة
يتكون بناء جملة التسلسل الاختياري .?
من ثلاثة أشكال:
-
obj?.prop
- ستُعيدobj.prop
إذا كان الكائنobj
موجودًا، وإلا ستعيد القيمةundefined
. -
obj?.[prop]
- ستُعيدobj[prop]
إذا كان الكائنobj
موجودًا، وإلا ستُعيدundefined
. -
obj?.method()
- تستدعيobj.method()
إذا كان الكائنobj
موجودًا، وإلا ستُعيدundefined
.
كما رأينا كل الطرق واضحة وسهلة الاستخدام. تتحقق .?
من الجزء الأيسر بحثًا عن قيمة فارغة أو غير معرفة null/undefined
ويسمح للتقييم بالمتابعة إذا لم يكن كذلك.
تسمح سلسلة .?
بالوصول الآمن إلى الخصائص المتداخلة. ومع ذلك، يجب أن نطبق .?
بحذر، وفقط في الحالات الّتي يكون فيها الجزء الأيسر غير موجود، حتى لا نخفي عن أنفسنا الأخطاء البرمجية إذا حدثت.
ترجمة -وبتصرف- للفصل Optional chaining '?.' من كتاب The JavaScript language
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.