ميزات JavaScript غير معروفة

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

الصورة

اليوم سنتحدث عن ميزات وخيارات JavaScript غير المعروفة لتطبيقها العملي.

جافا سكريبت دائما شيء جديد


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

→ الكود الذي سنناقشه هنا يمكن العثور عليه هنا.

يرجى ملاحظة أنني لم أضمّن أشياء مثل رفع المتغيرات والإغلاقات والكائنات الوكيل ووراثة النموذج الأولي وعدم التزامن / الانتظار والمولدات وما شابه ذلك. على الرغم من أن ميزات اللغة هذه يمكن أن تعزى إلى صعوبة الفهم ، إلا أنها غير معروفة جيدًا.

عامل باطل


جافا سكريبت لديه عامل void أحادي. ربما تكون قد صادفتها في صورة void(0) أو void 0 . الغرض الوحيد منه هو حساب التعبير إلى اليمين والعودة undefined . 0 هنا يتم استخدامه ببساطة لأنه معتاد ، على الرغم من أن هذا ليس ضروريًا ، وهنا يمكنك استخدام أي تعبير صالح. صحيح ، هذا المشغل سيعود في أي حال undefined .

 //  void void 0                  // undefined void (0)                // undefined void 'abc'              // undefined void {}                 // undefined void (1 === 1)          // undefined void (1 !== 1)          // undefined void anyfunction()      // undefined 

لماذا تضيف كلمة أساسية خاصة إلى اللغة التي تعمل على إرجاع undefined ، إذا كان يمكنك فقط استخدام القيمة القياسية undefined ؟ أليس كذلك ، هناك بعض التكرار؟

كما اتضح ، قبل ظهور معيار ES5 في معظم المتصفحات ، يمكن تعيين قيمة قياسية undefined بقيمة جديدة. لنفرض أنك تستطيع تنفيذ هذا الأمر بنجاح: undefined = "abc" . نتيجة لذلك ، قد لا تكون القيمة undefined كما يجب أن تكون. في تلك الأيام ، سمح لنا استخدام void بضمان الثقة في استخدام الحقيقي undefined .

الأقواس عند استدعاء المنشئات اختيارية


الأقواس التي تمت إضافتها بعد اسم الفئة ، والتي تستدعي المنشئ ، اختيارية بالكامل (ما لم يحتاج المنشئ إلى تمرير الوسائط).

في المثال التالي ، لا يؤثر وجود أو عدم وجود أقواس على التشغيل الصحيح للبرنامج.

 //     const date = new Date() const month = new Date().getMonth() const myInstance = new MyClass() //     const date = new Date const month = (new Date).getMonth() const myInstance = new MyClass 

لا يمكن استخدام الأقواس مع IIFE


لقد كان بناء جملة IIFE دائمًا غريبًا بالنسبة لي. لماذا هناك كل هذه الأقواس؟

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

 // IIFE (function () { console.log('Normal IIFE called') })() // Normal IIFE called void function () { console.log('Cool IIFE called') }() // Cool IIFE called 

يخبر عامل void هنا المحلل اللغوي أن الكود الذي يليه عبارة عن تعبير وظيفي. هذا يجعل من الممكن التخلص من الأقواس حول إعلان الوظيفة. وبالمناسبة ، هنا يمكنك استخدام أي عامل أحادي ( void ، + ، ! ، - ، وهلم جرا) ، وسيظل الرمز يعمل. أليس هذا رائعا؟

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

 // IIFE,    let result = (function () { // ... -  return 'Victor Sully' })() console.log(result) // Victor Sully let result1 = function () { // ... -  return 'Nathan Drake' }() console.log(result1) // Nathan Drake 

الأقواس حول IIFE الأولى فقط تحسين إمكانية قراءة التعليمات البرمجية دون التأثير على عملها.

إذا كنت ترغب في فهم IIFE بشكل أفضل ، ألق نظرة على هذه المواد.

البناء مع


هل تعلم أن JavaScript يحتوي على بنية تدعم كتل التعبير؟ يبدو مثل هذا:

 with (object)  statement //       with (object) {  statement  statement  ... } 

يضيف الإنشاء with كل خصائص الكائن الذي تم تمريره إليه في سلسلة النطاق المستخدمة عند تنفيذ الأوامر.

 //    with const person = { firstname: 'Nathan', lastname: 'Drake', age: 29 } with (person) { console.log(`${firstname} ${lastname} is ${age} years old`) } // Nathan Drake is 29 years old 

with قد يبدو وكأنه أداة عظيمة. يبدو الأمر أفضل من ميزات JS الجديدة لتدمير الكائنات ، لكن في الحقيقة ليست كذلك.

with البناء هو إهمال ولا ينصح للاستخدام. في وضع صارم ، ويحظر استخدامه. اتضح أنه with الكتل تسبب مشاكل في الأداء والأمان.

وظيفة منشئ


إن استخدام الكلمة function ليست الطريقة الوحيدة لتحديد وظيفة جديدة. يمكنك تحديد الوظائف بشكل ديناميكي باستخدام مُنشئ Function والمشغل new . هنا هو كيف يبدو.

 //  Function const multiply = new Function('x', 'y', 'return x*y') multiply(2,3) // 6 

الوسيطة الأخيرة التي تم تمريرها إلى المُنشئ هي سلسلة برمز الوظيفة. الوسائط الأخرى جهازي المعلمات الدالة.

من المثير للاهتمام أن نلاحظ أن مُنشئ Function هو "الأصل" لجميع المنشئات في JavaScript. حتى مُنشئ Object مُنشئ Function . ومنشئ Function الأصلي هو أيضا Function . نتيجة لذلك ، فإن استدعاء type object.constructor.constructor... الذي تم إجراؤه لأي كائن JS بعدد كافٍ من المرات سيعيد مُنشئ Function كنتيجة لذلك.

خصائص الميزة


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

متى يمكن أن تكون هناك حاجة لهذا؟

في الواقع ، هناك العديد من المواقف التي قد تكون فيها هذه الميزة مفيدة. النظر فيها.

▍ ميزات مخصصة


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

 //  ,   function greet () { if (greet.locale === 'fr') {   console.log('Bonjour!') } else if (greet.locale === 'es') {   console.log('Hola!') } else {   console.log('Hello!') } } greet() // Hello! greet.locale = 'fr' greet() // Bonjour! 

with وظائف مع المتغيرات الساكنة


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

ولكن ماذا لو احتجنا إلى المرونة ، وإذا كنا بحاجة إلى قراءة أو حتى تعديل قيمة هذا العداد وليس تسد النطاق العالمي؟

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

 //  ,   function generateNumber () { if (!generateNumber.counter) {   generateNumber.counter = 0 } return ++generateNumber.counter } console.log(generateNumber()) // 1 console.log(generateNumber()) // 2 console.log('current counter value: ', generateNumber.counter) // current counter value: 2 generateNumber.counter = 10 console.log('current counter value: ', generateNumber.counter) // current counter value: 10 console.log(generateNumber()) // 11 

خصائص كائن الوسيطات


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

  • يحتوي arguments.callee على ارتباط إلى الوظيفة الحالية.
  • يحتوي arguments.caller على مرجع للدالة التي تسمى الوظيفة الحالية.

النظر في مثال.

 //  callee  caller  arguments const myFunction = function () { console.log('Current function: ', arguments.callee.name) console.log('Invoked by function: ', arguments.callee.caller.name) } void function main () { myFunction() } () // Current function: myFunction // Invoked by function: main 

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

الكلمات الدلالية قالب الحرف


بالتأكيد ، إذا كان لديك أي شيء يتعلق ببرمجة JavaScript ، فقد سمعت عن القوالب الحرفية . تعد القوالب الحرفية واحدة من العديد من الابتكارات العظيمة لمعيار ES6. ومع ذلك ، هل تعرف عن القوالب الحرفية الموسومة؟

 //    `Hello ${username}!` //    myTag`Hello ${username}!` 

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

في المثال التالي ، لدينا علامة ، highlight ، يفسر البيانات من قالب حرفي ويدمج هذه البيانات في السطر النهائي ، ووضعها في <mark> HTML <mark> لتحديده عندما يتم عرض هذا النص على صفحة ويب.

 //    function highlight(strings, ...values) { //  i -      let result = '' strings.forEach((str, i) => {   result += str   if (values[i]) {     result += `<mark>${values[i]}</mark>`   } }) return result } const author = 'Henry Avery' const statement = `I am a man of fortune & I must seek my fortune` const quote = highlight`${author} once said, ${statement}` // <mark>Henry Avery</mark> once said, <mark>I am a man of fortune // & I must seek my fortune</mark> 

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


الحروف والرسائل في ES5


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

لكن العمل مع الخصائص لا يجب أن يكون بدائيًا على الإطلاق. كائنات JS تنفذ مفهوم getters و setters. بدلاً من إرجاع قيمة بعض خاصية الكائن مباشرةً ، يمكننا كتابة دالة getter الخاصة بنا ، والتي تُرجع ما نعتبره ضروريًا. الأمر نفسه ينطبق على كتابة قيم جديدة للخصائص باستخدام وظائف setter.

تتيح لك Getters and setters تنفيذ مخططات متقدمة للعمل مع الخصائص. عند قراءة خصائص الكتابة أو كتابتها ، يمكنك استخدام مفاهيم الحقول الافتراضية ، ويمكنك التحقق من قيم الحقول ، وعند الكتابة أو القراءة ، يمكن أن تحدث بعض الآثار الجانبية المفيدة.

 //    const user = { firstName: 'Nathan', lastName: 'Drake', // fullname -    get fullName() {   return this.firstName + ' ' + this.lastName }, //      set age(value) {   if (isNaN(value)) throw Error('Age has to be a number')   this._age = Number(value) }, get age() {   return this._age } } console.log(user.fullName) // Nathan Drake user.firstName = 'Francis' console.log(user.fullName) // Francis Drake user.age = '29' console.log(user.age) // 29 // user.age = 'invalid text' // Error: Age has to be a number 

Getters و setters ليست ES5 الابتكارات القياسية. كانوا دائما حاضرين في اللغة. في ES5 ، تمت إضافة أدوات بناء جملة ملائمة فقط للعمل معها. يمكن الاطلاع هنا على التفاصيل المتعلقة بالألعاب والمستوطنين.

تتضمن أمثلة استخدام getters مكتبة Node.js Colors الشائعة.

تقوم هذه المكتبة بتوسيع فئة String وإضافة العديد من أساليب getter إليها. يسمح لك هذا بتحويل سلسلة إلى نسختها "الملونة" بحيث يمكن عندئذٍ استخدام هذه السلسلة للتسجيل. يتم ذلك عن طريق العمل مع خصائص السلسلة.

مشغل فاصلة


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

 let result = expression1, expression2,... expressionN 

هنا ، سيتم حساب قيم جميع التعبيرات ، وبعد ذلك تدخل قيمة تعبير N في متغير result .

من المحتمل أنك قد استخدمت بالفعل مشغل الفاصلة للحلقات.

 for (var a = 0, b = 10; a <= 10; a++, b--) 

في بعض الأحيان يكون هذا المشغل مفيدًا جدًا عندما تحتاج إلى كتابة تعبيرات متعددة على نفس السطر.

 function getNextValue() {   return counter++, console.log(counter), counter } 

يمكن أن يكون مفيدًا عند تصميم وظائف السهم الصغير.

 const getSquare = x => (console.log (x), x * x) 

زائد المشغل


إذا كنت بحاجة إلى تحويل سلسلة بسرعة إلى رقم ، فإن عامل التشغيل plus مفيد لك. إنه قادر على العمل مع مجموعة متنوعة من الأرقام ، وليس فقط ، كما قد يبدو ، بأعداد إيجابية. نحن نتحدث عن الأرقام السالبة والثمانية والسداسية عشرية والأرقام بترميز الأسي. علاوة على ذلك ، فإنه قادر على تحويل كائنات Date وكائنات مكتبة Moment.js إلى طوابع زمنية.

 //  "" +'9.11'          // 9.11 +'-4'            // -4 +'0xFF'          // 255 +true            // 1 +'123e-5'        // 0.00123 +false           // 0 +null            // 0 +'Infinity'      // Infinity +'1,234'         // NaN +new Date      // 1542975502981 ( ) +momentObject    // 1542975502981 ( ) 

علامة تعجب مزدوجة


تجدر الإشارة إلى أن ما يسمى أحيانًا "عامل علامة التعجب المزدوج" (Bang Bang أو Double Bang) ليس في الواقع مشغلًا. هذا هو عامل NOT منطقي ، أو عامل إنكار منطقي يبدو وكأنه علامة تعجب تتكرر مرتين. تعد علامة التعجب المزدوج جيدة لأنها تتيح لك تحويل أي تعبير إلى قيمة منطقية. إذا كان التعبير ، من وجهة نظر JS ، صحيحًا - بعد معالجته بعلامة تعجب مزدوجة ، سيتم إرجاع true . خلاف ذلك ، سوف تعاد false .

 //     !!null            // false !!undefined       // false !!false           // false !!true            // true !!""              // false !!"string"        // true !!0               // false !!1               // true !!{}              // true !![]              // true 

عامل إنكار bitwise


دعونا نواجه الأمر: لا أحد يهتم بمشغلات bitwise. أنا لا أتحدث عن استخدامها. ومع ذلك ، يمكن استخدام عامل إنكار bitwise في العديد من الحالات.

عندما يتم تطبيق عامل التشغيل هذا على الأرقام ، فإنه يحولها كما يلي: من الرقم N ظهر -(N+1) . مثل هذا التعبير يعطي 0 إذا كانت N هي -1 .

يمكن استخدام هذه الميزة مع طريقة indexOf() عند استخدامها للتحقق من وجود عنصر في صفيف أو في سلسلة ، لأن هذه الطريقة ترجع -1 إذا لم يتم العثور على العنصر.

 //      indexOf let username = "Nathan Drake" if (~username.indexOf("Drake")) { console.log('Access denied') } else { console.log('Access granted') } 

تجدر الإشارة إلى أنه في معايير ES6 و ES7 ، على التوالي ، للسلاسل والمصفوفات ، ظهرت طريقة includes() . هو بالتأكيد أكثر ملاءمة لتحديد وجود عناصر من استخدام معامل النفي bitwise و indexOf() .

كتل اسمه


يحتوي JavaScript على مفهوم التسميات ، والذي يمكنك من خلاله تعيين أسماء (علامات) للحلقات. يمكنك بعد ذلك استخدام هذه التسميات للإشارة إلى الحلقة المناسبة عند تطبيق عبارات break أو continue . يمكن أيضًا تعيين العلامات إلى كتل التعليمات البرمجية العادية.

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

 //    declarationBlock: { //       //     var i, j } forLoop1: //     - "forLoop1" for (i = 0; i < 3; i++) {       forLoop2: //     -  "forLoop2"  for (j = 0; j < 3; j++) {       if (i === 1 && j === 1) {        continue forLoop1     }     console.log('i = ' + i + ', j = ' + j)  } } /* i = 0, j = 0 i = 0, j = 1 i = 0, j = 2 i = 1, j = 0 i = 2, j = 0 i = 2, j = 1 i = 2, j = 2 */ //      loopBlock4: { console.log('I will print') break loopBlock4 console.log('I will not print') } // I will print 

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

ملخص


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

أعزائي القراء! إذا كنت تعرف بعض ميزات JS غير المعروفة وشاهدت خيارات لتطبيقها العملي ، فيرجى إخبارنا بها.

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


All Articles