جافا سكريبت ES6: نقاط الضعف

في يونيو 2018 ، احتفل معيار ECMAScript 2015 ( ES6 ) بمرور ثلاث سنوات على إنشائه. في ES6 ، أولاً ، ظهرت العديد من ميزات JavaScript الجديدة ، وثانيًا ، يبدأ عصر جديد من تطوير اللغة بهذا المعيار. بالإضافة إلى ذلك ، كان هذا آخر إصدار على نطاق واسع من JS ، حيث يقوم TC39 الآن بتطبيق مخطط إصدار الإصدارات السنوية الصغيرة من المعيار ، ولا يتم طرحه مرة أخرى كل بضع سنوات.



لقد جذبت السنوات الأربع الماضية ، ES6 ، المبرر تمامًا ، اهتمامًا عالميًا. يقول مؤلف المادة ، التي ننشر ترجمتها اليوم ، أنه طوال هذا الوقت ، وبفضل بابل ، كتب جميع الشفرات باستخدام النسخة الحديثة من مواصفات JS. ويعتقد أن الوقت الكافي قد مر للتحليل النقدي للميزات الجديدة لـ ES6. على وجه الخصوص ، فهو مهتم بما استخدمه لبعض الوقت ، ثم توقف عن استخدامه لأنه أدى إلى تفاقم رمزه.

حول نقاط ضعف JS


كتب دوغلاس كروكفورد ، في كتابه JavaScript: Strengths ، أيضًا ما يمكن اعتباره نقاط ضعف في اللغة. هذا شيء ، في رأيه ، لا يستحق استخدامه. لحسن الحظ ، من بين ابتكارات ES6 ، لا يوجد شيء قبيح مثل بعض الميزات الإشكالية القديمة لـ JS ، مثل عامل المساواة المتراخي الذي يقوم بتحويل النوع الضمني ، ووظيفة eval() ، eval() with . تم تصميم الميزات الجديدة لـ ES6 بشكل أفضل. ومع ذلك ، هناك بعض الأشياء التي أتجنبها. تلك الميزات الموجودة في قائمة "نقاط الضعف" في JS موجودة في هذه القائمة للأسباب التالية:

  • إنها في جوهرها "أفخاخ". أي ، يبدو أنها مصممة لأداء إجراءات معينة ، وفي معظم الحالات ، تعمل كما هو متوقع. ومع ذلك ، في بعض الأحيان يتصرفون بشكل غير متوقع ، مما قد يؤدي بسهولة إلى الأخطاء.
  • إنها تزيد من حجم اللغة مقابل فوائد صغيرة. تمنح هذه الفرص للمطور بعض الميزات الصغيرة ، ولكنها تتطلب من شخص يحاول معرفة رمزه أن يكون لديه معرفة بآليات معينة ، عادة ما تكون مخفية في مكان ما. وينطبق هذا بشكل مضاعف على إمكانات واجهة برمجة التطبيقات ، عند استخدام هذه الميزة يعني أن التعليمات البرمجية الأخرى التي تتفاعل مع التعليمات البرمجية التي كتبها مطور معين يجب أن تكون على دراية بتطبيق ميزة واجهة برمجة التطبيقات هذه.

الآن ، مسترشداً بهذه الاعتبارات ، دعنا نتحدث عن نقاط الضعف في ES6.

ثابت الكلمات الرئيسية


قبل ES6 ، يمكن التصريح عن المتغيرات في JavaScript باستخدام الكلمة var . بالإضافة إلى ذلك ، لا يمكن الإعلان عن المتغيرات على الإطلاق ، ثم ، حتى إذا تم استخدامها في الوظائف ، تقع في النطاق العالمي. يمكن أن تلعب خصائص الكائنات دور المتغيرات ، ويتم الإعلان عن function باستخدام الكلمة الأساسية function . تحتوي الكلمة الرئيسية var على ميزات معينة.

لذلك ، يسمح لك بإنشاء متغيرات مضافة إلى الكائن العام ، أو تلك التي يكون نطاقها محدودًا بالوظائف. ومع ذلك ، فإن الكلمة الأساسية var لا تنتبه إلى كتل التعليمات البرمجية. بالإضافة إلى ذلك ، يمكنك الرجوع إلى متغير معلن باستخدام الكلمة الأساسية var في الرمز الموجود قبل الأمر لإعلانه. تُعرف هذه الظاهرة برفع المتغيرات. هذه الميزات ، إذا لم تؤخذ في الاعتبار ، يمكن أن تؤدي إلى أخطاء. من أجل تصحيح الوضع ، قدم ES6 كلمتين رئيسيتين جديدتين لتعريف المتغيرات: let and const . قاموا بحل المشاكل الرئيسية. وبالتحديد ، نحن نتحدث عن حقيقة أن المتغيرات المعلنة باستخدام هذه الكلمات الرئيسية لها نطاق حظر ، ونتيجة لذلك ، على سبيل المثال ، متغير معلن في حلقة غير مرئي خارجها. بالإضافة إلى ذلك ، لا يسمح استخدام let و const بالوصول إلى المتغيرات قبل الإعلان عنها. سيؤدي ذلك إلى خطأ ReferenceError . كانت هذه خطوة كبيرة إلى الأمام. ومع ذلك ، أدى ظهور كلمتين رئيسيتين جديدتين ، بالإضافة إلى ميزاتها ، إلى مزيد من الارتباك.

لا يمكن استبدال قيمة المتغير (الثابت) المعلن باستخدام الكلمة الأساسية const بعد الإعلان. هذا هو الفرق الوحيد بين const let . تبدو هذه الفرصة الجديدة مفيدة ، ويمكنها بالفعل تحقيق بعض الفائدة. المشكلة هي الكلمة الأساسية const نفسها. لا تتوافق الطريقة التي صرحت بها الثوابت في سلوكها مع ما يربطه معظم المطورين بمفهوم "ثابت".

 const CONSTANT = 123; //      "TypeError: invalid assignment to const `CONSTANT`" CONSTANT = 345; const CONSTANT_ARR = [] CONSTANT_ARR.push(1) //     [1]  -    console.log(CONSTANT_ARR) 

يؤدي استخدام الكلمة الأساسية const منع كتابة قيمة جديدة إلى ثابت ، ولكنه لا يجعل الكائنات المشار إليها بواسطة هذه الثوابت ثابتة. توفر هذه الميزة حماية ضعيفة ضد القيم المتغيرة عند العمل مع معظم أنواع البيانات. ونتيجة لذلك ، نظرًا لحقيقة أن استخدام const يمكن أن يؤدي إلى الارتباك ، وبسبب حقيقة أنه إذا كانت الكلمة الرئيسية let موجودة ، فإن وجود const يبدو متكررًا ، فقد قررت دائمًا استخدام let .

سلاسل قالب ذات علامات


تعتبر الكلمة الأساسية const مثالاً على كيفية إنشاء المواصفات لطرق كثيرة جدًا لحل عدد قليل جدًا من المشكلات. في حالة سلاسل القوالب ذات العلامات ، لدينا موقف معاكس. اعتبرت لجنة TC39 تركيب هذه السلاسل طريقة لحل استيفاء الأوتار والأوتار متعددة الخطوط. ثم قرروا توسيع هذه الفرصة من خلال استخدام وحدات الماكرو.

إذا لم يسبق لك أن رأيت سلاسل نمط مميزة من قبل ، فضع في اعتبارك أنها تشبه إلى حد ما زينة الأوتار. فيما يلي مثال للعمل معهم مع MDN :

 var person = 'Mike'; var age = 28; function myTag(strings, personExp, ageExp) { var str0 = strings[0]; // "that " var str1 = strings[1]; // " is a " //  (  ) //     , //  ,      . // var str2 = strings[2]; var ageStr; if (ageExp > 99){   ageStr = 'centenarian'; } else {   ageStr = 'youngster'; } return str0 + personExp + str1 + ageStr; } var output = myTag`that ${ person } is a ${ age }`; console.log(output); // that Mike is a youngster 

لا يمكن وصف سلاسل القوالب ذات العلامات بأنها عديمة الفائدة تمامًا. هنا لمحة عامة عن بعض استخداماتهم. على سبيل المثال ، فهي مفيدة في مسح كود HTML. وفي الوقت الحالي ، يوضح تطبيقهم النهج الأكثر دقة في المواقف التي تحتاج فيها إلى إجراء نفس العملية على جميع بيانات الإدخال الخاصة بقالب سلسلة تعسفي. ومع ذلك ، هذا نادر نسبيًا ، يمكنك القيام بنفس الشيء باستخدام واجهة برمجة التطبيقات المناسبة (على الرغم من أن هذا الحل أطول). ولحل معظم المشاكل ، لن يكون استخدام واجهة برمجة التطبيقات (API) أسوأ من استخدام سلاسل القوالب ذات العلامات. هذه الميزة لا تضيف ميزات جديدة للغة. تضيف أساليب جديدة للعمل مع البيانات التي يجب أن تكون مألوفة لأولئك الذين يجب عليهم قراءة التعليمات البرمجية المكتوبة باستخدام سلاسل القوالب ذات العلامات. وأنا أسعى لضمان بقاء الشفرة نظيفة ومفهومة قدر الإمكان.

تعبيرات التخصيص المدمرة المعاد تصميمها


تبدو بعض ميزات اللغة رائعة عند استخدامها لحل المهام البسيطة ، ولكن عندما تصبح المهام أكثر تعقيدًا ، يمكن أن تخرج هذه الميزات عن السيطرة. على سبيل المثال ، أحب العامل الشرطي الثلاثي:

 let conferenceCost = isStudent ? 50 : 200 

ومع ذلك ، فإن الرمز المكتوب بمساعدته ، يصبح من الصعب فهم ما إذا كنت ، باستخدام هذا العامل ، بدأت في استخدام الإنشاءات المتداخلة:

 let conferenceCost = isStudent ? hasDiscountCode ? 25 : 50 : hasDiscountCode ? 100 : 200; 

ويمكن قول الشيء نفسه عن المهمة المدمرة. تسمح لك هذه الآلية بسحب قيم المتغيرات من الكائنات أو المصفوفات:

 let {a} = {a: 2, b: 3}; let [b] = [4, 5]; console.log(a, b) // 2, 4 

بالإضافة إلى ذلك ، عند استخدامه ، يمكنك إعادة تسمية المتغيرات ، والحصول على قيم متداخلة ، وتعيين القيم الافتراضية:

 let {a: val1} = {a: 2, b: 3}; let [{b}] = [{a:3, b:4} , {c: 5, d: 6}]; let {c=6} = {a: 2, c: 5}; let {d=6} = {a: 2, c: 5}; console.log(val1, b, c, d) // 2, 4, 5, 6 

كل هذا رائع - حتى يتعلق الأمر ببناء تعبيرات معقدة باستخدام كل هذه الميزات. على سبيل المثال ، في التعبير أدناه ، تم التصريح عن 4 متغيرات: userName و eventType و eventDate و eventId . يتم أخذ قيمهم من أماكن مختلفة في بنية كائن eventRecord .

 let eventRecord = { user: { name: "Ben M", email: "ben@m.com" }, event: "logged in", metadata: { date: "10-10-2017" }, id: "123" }; let { user: { name: userName = "Unknown" }, event: eventType = "Unknown Event", metadata: [date: eventDate], id: eventId } = obj; 

لفهم مثل هذا الرمز يكاد يكون من المستحيل. يمكن حل هذه المشكلة باستخدام رمز أكثر قابلية للقراءة ، إذا كنت تستخدم العديد من عمليات التدمير أو التخلي عنها تمامًا.

 let eventRecord = { user: { name: "Ben M", email: "ben@m.com" }, event: "logged in", metadata: { date: "10-10-2017" }, id: "123" }; let userName = eventRecord.user.userName || 'Unknown'; let eventDate = eventRecord.metadata.date; let {event:eventType='UnknownEvent', id:eventId} = eventRecord; 

ليس لدي دليل واضح يشير إلى ضرورة إعادة صياغة التعبير عن المهمة المدمرة. ومع ذلك ، في كل مرة أنظر فيها إلى تعبير مشابه ولا أستطيع أن أفهم على الفور المشكلة التي تحلها ، وما هي المتغيرات المستخدمة فيها ، أفهم أن الوقت قد حان لتبسيط الكود من أجل تحسين قراءته.

التصدير الافتراضي


ES6 لديها ميزة واحدة لطيفة. وهو يتألف من كيفية تعامل مطوريها مع معايير ما تم القيام به سابقًا بمساعدة مكتبات مختلفة ، وغالبًا ما تتنافس مع بعضها البعض. حتى في المواصفات ظهرت الطبقات والوعود والوحدات. هذا هو كل ما استخدمه مجتمع مطوري JS قبل ES6 ، حيث وجدته في مكتبات الطرف الثالث. على سبيل المثال ، تعد وحدات ES6 بديلاً ممتازًا لما انسكب في حرب تنسيق AMD / CommonJS وتوفر بنية ملائمة لتنظيم عمليات الاستيراد.

تدعم وحدات ES6 طريقتين رئيسيتين لتصدير القيم: المسماة التصدير والتصدير الافتراضي ، أو التصدير الافتراضي:

 const mainValue = 'This is the default export export default mainValue export const secondaryValue = 'This is a secondary value; export const secondaryValue2 = 'This is another secondary value; 

يمكن للوحدة استخدام عدة أوامر تصدير مسماة ، ولكن أمر تصدير افتراضي واحد فقط. عند استيراد ما تم تصديره باستخدام أمر التصدير الافتراضي ، في ملف الاستيراد ، يمكنك إعطاء كل ما تم تصديره افتراضيًا أي اسم ، حيث لا يتم البحث عن أي أسماء أثناء هذه العملية. عند استخدام التصدير المسمى ، تحتاج إلى استخدام أسماء المتغيرات من ملفات التصدير ، على الرغم من أن إعادة التسمية ممكنة أيضًا.

 //   import renamedMainValue from './the-above-example'; //   import {secondaryValue} from './the-above-example'; //     import {secondaryValue as otherValue} from './the-above-example'; 

تمتعت عملية التصدير الافتراضية باهتمام خاص من قبل مطوري معيار ES6 ، وأنشأوا عن قصد بنية أبسط لذلك. ومع ذلك ، من الناحية العملية ، تمكنت من معرفة أن استخدام تقنية التصدير المسماة هو الأفضل للأسباب التالية.

  1. عند استخدام التصدير المسمى ، تتوافق أسماء المتغيرات المصدرة ، بشكل افتراضي ، مع أسماء المتغيرات المستوردة ، مما يبسط البحث عن أولئك الذين لا يستخدمون أدوات تطوير ذكية.
  2. عند استخدام عمليات تصدير مسماة ، يحصل المبرمجون الذين يستخدمون أدوات التطوير الذكية على ميزات ملائمة مثل الاستيراد التلقائي .
  3. تمكنك عمليات التصدير المسماة من تصدير أي شيء تريده بشكل موحد من الوحدات بالكميات الصحيحة. يحد التصدير الافتراضي المطور من تصدير قيمة واحدة فقط. كحل مؤقت ، يمكنك تطبيق تصدير كائن بعدة خصائص. ومع ذلك ، يفقد هذا النهج قيمة خوارزمية اهتزاز الأشجار المستخدمة لتقليل حجم تطبيقات JS التي تم إنشاؤها بواسطة شيء مثل webpack. إن استخدام الوحدات المسماة بالاسم الحصري يبسط العمل.

بشكل عام ، يمكن ملاحظة أن تسمية الكيانات هي ممارسة جيدة ، لأنها تتيح لك التعرف عليها بشكل فريد في الشفرة وفي المحادثات حول هذا الرمز. هذا هو السبب في أنني أستخدم التصدير المسمى.

الملخص


لقد تعلمت للتو عن ميزات ES6 ، والتي ، وفقًا لمؤلف هذه المادة ، غير ناجحة. ربما تنضم إلى هذا الرأي ، ربما لا. أي لغة برمجة هي نظام معقد ، يمكن عرض إمكاناته من وجهات نظر مختلفة. ومع ذلك ، نأمل أن تكون هذه المقالة مفيدة لجميع أولئك الذين يسعون إلى كتابة كود واضح وعالي الجودة.

أعزائي القراء! هل هناك شيء ما في جافا سكريبت حديث تحاول تجنبه؟

Source: https://habr.com/ru/post/ar417383/


All Articles