ابتكارات JavaScript: نتائج Google I / O 2019. الجزء الأول

المواد ، الجزء الأول من الترجمة التي ننشرها اليوم ، مكرسة لميزات JavaScript القياسية الجديدة التي تمت مناقشتها في مؤتمر Google I / O 2019 . على وجه الخصوص ، هنا سنتحدث عن التعبيرات المعتادة ، حول حقول الفصل ، حول العمل بالسلاسل.



الشيكات التعبير العادية


التعبيرات العادية (التعبير العادي ، اختصارًا - RegEx أو RegExp) هي تقنية قوية لمعالجة السلسلة يتم تنفيذها في العديد من لغات البرمجة. تعد التعبيرات العادية مفيدة للغاية في الحالات التي تحتاج فيها ، على سبيل المثال ، للبحث عن أجزاء من السلاسل النصية المعقدة. حتى وقت قريب ، كان لتطبيق جافا سكريبت التعبيرات العادية كل شيء باستثناء lookbackhinds.

من أجل فهم ماهية الفحص بأثر رجعي ، دعونا نتحدث أولاً عن رؤوس النظافة المدعومة بالفعل في JavaScript.

الجزء الثاني

▍ الاختيار المسبق


يسمح لك بناء جملة الشيكات البادئة في التعبيرات العادية بالبحث عن أجزاء من السلاسل عندما يكون معروفًا أن الأجزاء الأخرى على يمينها. على سبيل المثال ، عند العمل مع السلسلة MangoJuice, VanillaShake, GrapeJuice يمكنك استخدام بناء جملة الاختيار الإيجابي الإيجابي للعثور على الكلمات التي تليها مباشرة كلمة Juice . في حالتنا ، هذه هي الكلمات Mango Grape .

هناك نوعان من الشيكات الرائدة. هذه هي المظاهر الإيجابية والمظاهر السلبية.

الاختيار يؤدي الإيجابية


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

 /[a-zA-Z]+(?=Juice)/ 

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

 const testString = "MangoJuice, VanillaShake, GrapeJuice"; const testRegExp = /[a-zA-Z]+(?=Juice)/g; const matches = testString.match( testRegExp ); console.log( matches ); // ["Mango", "Grape"] 

تحقق الرصاص السلبي


إذا أخذنا في الاعتبار ، باستخدام السطر أعلاه ، آلية عمل الفحوصات السلبية الأولية ، اتضح أنها تسمح لك بالعثور على الكلمات التي ليس لها كلمة Juice . يشبه بناء الجملة الشيكات السالبة بناء جملة الشيكات الإيجابية. ومع ذلك ، هناك ميزة واحدة فيه ، وهي أن الرمز = (يساوي) يتغير إلى رمز ! (علامة التعجب). إليك ما يبدو عليه:

 /[a-zA-Z]+(?!Juice)/ 

يسمح لك هذا التعبير المنتظم بتحديد كل الكلمات الموجودة على اليمين والتي لا توجد بها كلمة Juice . ولكن عند تطبيق مثل هذا القالب ، سيتم اختيار كل الكلمات الموجودة في السطر ( MangoJuice, VanillaShake, GrapeJuice ). والحقيقة هي أنه وفقًا للنظام ، لا توجد كلمة واحدة هنا تنتهي بـ Juice . نتيجة لذلك ، من أجل تحقيق النتيجة المرجوة ، تحتاج إلى توضيح التعبير العادي وإعادة كتابته مثل هذا:

 /(Mango|Vanilla|Grape)(?!Juice)/ 

يتيح لك استخدام هذا القالب تحديد الكلمات Mango أو Vanilla أو Grape ، وبعدها لا توجد كلمة Juice . هنا مثال:

 const testString = "MangoJuice, VanillaShake, GrapeJuice"; const testRegExp = /(Mango|Vanilla|Grape)(?!Juice)/g; const matches = testString.match( testRegExp ); console.log( matches ); // ["Vanilla"] 

Check تحقق بأثر رجعي


قياسًا على بناء جملة الاختبارات الأولية ، يتيح لك بناء الجملة لعمليات التحقق بأثر رجعي تحديد تسلسل من الأحرف فقط إذا كان على يسار هذه التسلسلات نمط معين. على سبيل المثال ، عند معالجة السلسلة FrozenBananas, DriedApples, FrozenFish يمكننا استخدام فحص استعادي إيجابي للعثور على الكلمات الموجودة على اليسار والتي توجد بها الكلمة Frozen . في حالتنا ، تتوافق عبارة " Bananas Fish مع هذا الشرط.

هناك ، كما هو الحال مع الشيكات الرائدة ، اختبارات إيجابية بأثر رجعي (نظرة إيجابية إلى الوراء) وشيكات بأثر رجعي سلبية (نظرة سلبية أو سلبية).

مراجعة بأثر رجعي إيجابية


يتم استخدام الاختبارات الإيجابية بأثر رجعي للبحث عن أنماط إلى اليسار منها أنماط أخرى. فيما يلي مثال على بناء الجملة المستخدم لوصف مثل هذه الاختبارات:

 /(?<=Frozen)[a-zA-Z]+/ 

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

 const testString = "FrozenBananas, DriedApples, FrozenFish"; const testRegExp = /(?<=Frozen)[a-zA-Z]+/g; const matches = testString.match( testRegExp ); console.log( matches ); // ["Bananas", "Fish"] 

التحقق بأثر رجعي السلبي


تتيح لك آلية عمليات الفحص بأثر رجعي السلبية البحث عن الأنماط الموجودة في الخطوط التي ليس لها نمط محدد. على سبيل المثال ، إذا كنت بحاجة إلى تحديد الكلمات التي لا تبدأ بـ Frozen في FrozenBananas, DriedApples, FrozenFish ، فيمكنك محاولة استخدام هذا التعبير العادي:

 /(?<!Frozen)[a-zA-Z]+/ 

ولكن بما أن استخدام هذا البناء سيؤدي إلى اختيار كل الكلمات من السلسلة ، حيث أن أيا منها يبدأ بـ Frozen ، يجب توضيح التعبير العادي:

 /(?<!Frozen)(Bananas|Apples|Fish)/ 

هنا مثال:

 const testString = "FrozenBananas, DriedApples, FrozenFish"; const testRegExp = /(?<!Frozen)(Bananas|Apples|Fish)/g; const matches = testString.match( testRegExp ); console.log( matches ); // ["Apples"] 

→ الدعم


سيقدم هذا القسم والأقسام المشابهة الأخرى معلومات عن مرحلة تنسيق الميزات الموصوفة لـ JS في اللجنة الفنية 39 (اللجنة الفنية 39 ، TC39) ، المسؤولة في ECMA International عن دعم مواصفات ECMAScript. ستوفر هذه الأقسام أيضًا بيانات حول إصدارات Chrome و Node.js (وأحيانًا على إصدار Firefox) ، بدءًا من ذلك يمكنك استخدام الميزات المقابلة.


حقول الصف


حقل الفئة عبارة عن بناء جملة جديد يستخدم لتحديد خصائص مثيلات الفئة (كائنات) خارج مُنشئ الفصل. هناك نوعان من حقول الفصل: حقول الفئة العامة وحقول الفصل الخاص.

class حقول الطبقة العامة


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

 class Dog {    constructor() {        this.name = 'Tommy';    } } 

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

 class Animal {} class Dog extends Animal {    constructor() {        super(); //  super   `this`          this.sound = 'Woof! Woof!';    }    makeSound() {        console.log( this.sound );    } } //    const tommy = new Dog(); tommy.makeSound(); // Woof! Woof! 

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

 class Animal {} class Dog extends Animal {    sound = 'Woof! Woof!'; //       makeSound() {        console.log( this.sound );    } } //    const tommy = new Dog(); tommy.makeSound(); // Woof! Woof! 

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

 class Animal {    constructor( ...args ) {        console.log( 'Animal args:', args );    } } class Dog extends Animal {    sound = 'Woof! Woof!'; //    makeSound() {        console.log( this.sound );    } } //    const tommy = new Dog( 'Tommy', 'Loves', 'Toys!' ); tommy.makeSound(); // Animal args: [ 'Tommy', 'Loves', 'Toys!' ] 

class حقول الصف الخاص


كما تعلمون ، في JavaScript لا توجد معدّلات وصول إلى حقول الفصل مثل public أو private أو protected . جميع خصائص الكائنات عامة بشكل افتراضي. هذا يعني أن الوصول إليهم غير محدود. إن الأقرب إلى إجراء خاصية لكائن مماثل للخاصية هو استخدام نوع بيانات Symbol . هذا يسمح لك بإخفاء خصائص الكائنات من العالم الخارجي. ربما تكون قد استخدمت أسماء خصائص مسبوقة بـ _ (تسطير سفلي) للإشارة إلى أنه ينبغي اعتبار الخصائص المطابقة مخصصة للاستخدام فقط داخل الكائن. ومع ذلك ، هذا مجرد نوع من الإخطار لأولئك الذين سيستخدمون المنشأة. هذا لا يحل مشكلة التقييد الحقيقي للوصول إلى العقارات.

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

 class Dog {    _sound = 'Woof! Woof!'; //            makeSound() {        console.log( this._sound );    } } //    const tommy = new Dog(); console.log( tommy._sound ); // Woof! Woof! 

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

 SyntaxError: Undefined private field 

هنا مثال:

 class Dog {    #sound = 'Woof! Woof!'; //  -      makeSound() {        console.log( this.#sound );    } } //    const tommy = new Dog(); tommy.makeSound() // Woof! Woof! //console.log( tommy.#sound ); // SyntaxError 

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

يمكن الإعلان عن الحقول الخاصة (والعامة) دون كتابة قيم معينة فيها:

 class Dog {    #name;    constructor( name ) {        this.#name = name;    }    showName() {        console.log( this.#name );    } } //    const tommy = new Dog( 'Tommy' ); tommy.showName(); // Tommy 

→ الدعم



أسلوب السلسلة .matchAll ()


يحتوي النموذج الأولي لنوع بيانات String على طريقة .match() تقوم بإرجاع صفيف من أجزاء السلسلة التي تطابق الشرط المحدد بواسطة التعبير العادي. هنا مثال باستخدام هذه الطريقة:

 const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /([A-Z0-9]+)/g; console.log( colors.match( matchColorRegExp ) ); // : ["EEE", "CCC", "FAFAFA", "F00", "000"] 

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

 const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /#([A-Z0-9]+)/; console.log( colors.match( matchColorRegExp ) ); // : (       ) ["#EEE", "EEE", index: 0, input: "<colors>"] 

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

 const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /#([A-Z0-9]+)/g; //        , // Uncaught ReferenceError: match is not defined while( match = matchColorRegExp.exec( colors ) ) {  console.log( match ); } // : (       ) ["#EEE", "EEE", index: 0, input: "<colors>"] ["#CCC", "CCC", index: 6, input: "<colors>"] ["#FAFAFA", "FAFAFA", index: 12, input: "<colors>"] ["#F00", "F00", index: 21, input: input: "<colors>"] ["#000", "000", index: 27, input: input: "<colors>"] 

لحل هذه المشكلات ، يمكننا الآن استخدام طريقة السلسلة .matchAll() ، والتي تُرجع .matchAll() . .next() كل استدعاء إلى الأسلوب .next() من هذا التكرار العنصر التالي من نتائج البحث. نتيجة لذلك ، يمكن إعادة كتابة المثال أعلاه على النحو التالي:

 const colors = "#EEE, #CCC, #FAFAFA, #F00, #000"; const matchColorRegExp = /#([A-Z0-9]+)/g; console.log( ...colors.matchAll( matchColorRegExp ) ); // : (       ) ["#EEE", "EEE", index: 0, input: "<colors>"] ["#CCC", "CCC", index: 6, input: "<colors>"] ["#FAFAFA", "FAFAFA", index: 12, input: "<colors>"] ["#F00", "F00", index: 21, input: input: "<colors>"] ["#000", "000", index: 27, input: input: "<colors>"] 

→ الدعم



المجموعات المسماة في التعبيرات العادية


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

سوف تنعكس شظايا السلسلة التي استولت عليها المجموعة في نتائج تطبيق التعبير العادي.

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

 ["#EEE", "EEE", index: 0, input: "<colors>"] 

إذا كانت هناك عدة مجموعات في التعبير العادي ، فسوف تدخل في نتائج معالجة السلسلة بترتيب وصفها في التعبير العادي. النظر في مثال:

 const str = "My name is John Doe."; const matchRegExp = /My name is ([az]+) ([az]+)/i; const result = str.match( matchRegExp );console.log( result ); //   result  null -   console.log( { firstName: result[1], lastName: result[2] } ); // : ["My name is John Doe", "John", "Doe", index: 0, input: "My name is John Doe.", groups: undefined] {firstName: "John", lastName: "Doe"} 

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

يتيح لك استخدام المجموعات المسماة حفظ المجموعات التي تلتقطها داخل كائن groups ، والتي تتوافق أسماء ممتلكاتها مع الأسماء المعينة للمجموعات.

 const str = "My name is John Doe."; const matchRegExp = /My name is (?<firstName>[az]+) (?<lastName>[az]+)/i; const result = str.match( matchRegExp ); console.log( result ); console.log( result.groups ); // : ["My name is John Doe", "John", "Doe", index: 0, input: "My name is John Doe.", groups: {firstName: "John", lastName: "Doe"}] {firstName: "John", lastName: "Doe"} 

تجدر الإشارة إلى أن المجموعات المسماة تعمل بشكل جيد مع طريقة .matchAll() .

→ الدعم



أن تستمر ...

أعزائي القراء! هل استخدمت أيًا من ابتكارات JavaScript الموضحة هنا؟

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


All Articles