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

اليوم ننشر الجزء الثاني من ترجمة ابتكارات JavaScript. هنا نتحدث عن فواصل من أرقام الأرقام ، عن أرقام BigInt ، وعن العمل مع المصفوفات والكائنات ، وعن globalThis ، وعن الفرز ، وعن API globalThis وعن الوعود.



الجزء الأول

فواصل الرقم


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

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

 var billion = 1_000_000_000; console.log( billion ); // 1000000000 

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

 console.log( 1_000_000_000.11 ); // 1000000000.11 console.log( 1_000_000_000.1_012 ); // 1000000000.1012 console.log( 0xFF_00_FF ); // 16711935 console.log( 0b1001_0011 ); // 147 console.log( 0o11_17 ); // 591 

→ الدعم



نوع بيانات Bigint


يتم إنشاء الأرقام في JavaScript باستخدام دالة مُنشئ Number .

القيمة القصوى التي يمكن تمثيلها بأمان باستخدام نوع بيانات Number هي (2⁵³ - 1) ، أي 9007199254740991. يمكنك رؤية هذا الرقم باستخدام Number.MAX_SAFE_INTEGER .

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

ماذا سيحدث إذا حاولنا إضافة شيء إلى الرقم 9007199254740991؟

 console.log( Number.MAX_SAFE_INTEGER ); // 9007199254740991 console.log( Number.MAX_SAFE_INTEGER + 10 ); // 9007199254741000 

نتيجة إضافة Number.MAX_SAFE_INTEGER و 10 ، الإخراج الثاني من console.log() ، غير صحيحة. هذا يرجع إلى حقيقة أن JS لا يمكنها إجراء العمليات الحسابية بأرقام أكبر من قيمة Number.MAX_SAFE_INTEGER . يمكنك التعامل مع هذه المشكلة باستخدام bigint بيانات bigint .

يسمح bigint نوع bigint بتمثيل أعداد صحيحة أكبر من Number.MAX_SAFE_INTEGER . العمل مع قيم BigInt يشبه العمل مع قيم type Number . على وجه الخصوص ، تحتوي اللغة على وظيفة BigInt() ، والتي يمكنك من خلالها إنشاء القيم المقابلة ، ونوع بيانات bigint البدائية المضمنة المستخدمة لتمثيل أعداد صحيحة كبيرة.

 var large = BigInt( 9007199254740991 ); console.log( large ); // 9007199254740991n console.log( typeof large ); // bigint 

يضيف JavaScript n إلى نهاية BigInt الحرفية. بالنسبة لنا ، هذا يعني أنه يمكن كتابة هذه القيم الحرفية بإضافة n إلى نهاية الأعداد الصحيحة.

الآن وبعد أن أصبح لدينا أرقام BigInt تحت تصرفنا ، يمكننا إجراء عمليات رياضية بأمان على أعداد كبيرة من النوع bigint .

 var large = 9007199254740991n; console.log( large + 10n ); // 9007199254741001n 

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

تجدر الإشارة إلى أن الدالة BigInt() يمكن أن تأخذ أرقامًا مختلفة: عشري ، ثنائي ، ست عشري ، ثماني. داخل هذه الوظيفة ، سيتم تحويلها إلى أرقام ، من أجل تمثيل نظام الأرقام العشرية فيها.

يدعم نوع bigint أيضًا فواصل البت:

 var large = 9_007_199_254_741_001n; console.log( large ); // 9007199254741001n 

→ الدعم



أساليب صفيف جديدة: .flat () و. flatMap ()


سنتحدث هنا عن أساليب النموذج الأولي الجديدة لكائن Array - .flat() و. .flatMap() .

طريقة fl. flat ()


الآن كائنات من النوع Array لديها طريقة جديدة -. .flat(n) . تقوم بإرجاع صفيف جديد ، مما يسمح بشكل متكرر برفع عناصر المصفوفات إلى المستوى المحدد n . بشكل افتراضي ، n هي 1. هذه الطريقة يمكن أن تمرر n تساوي Infinity ، مما يسمح لك بتحويل صفيف مع صفائف متداخلة إلى صفيف أحادي البعد.

 var nums = [1, [2, [3, [4, 5]]]]; console.log( nums.flat() ); // [1, 2, [3, [4,5]]] console.log( nums.flat(2) ); // [1, 2, 3, [4,5]] console.log( nums.flat(Infinity) ); // [1, 2, 3, 4, 5] 

→ الدعم



طريقة FlatMap ()


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

 var nums = [1, 2, 3]; var squares = nums.map( n => [ n, n*n ] ) console.log( squares ); // [[1,1],[2,4],[3,9]] console.log( squares.flat() ); // [1, 1, 2, 4, 3, 9] 

يمكن تبسيط حل هذه المشكلة باستخدام طريقة. .flatMap() . يقوم بتحويل الصفائف التي تم إرجاعها بواسطة دالة رد الاتصال التي تم تمريرها إليها ، تمامًا كما أنها ستحول طريقة .flat() مع المعلمة n تساوي 1.

 var nums = [1, 2, 3]; var makeSquare = n => [ n, n*n ]; console.log( nums.flatMap( makeSquare ) ); // [1, 1, 2, 4, 3, 9] 

→ الدعم



▍ طريقة Object.fromEntries ()


من الممكن استخراج أزواج من نوع : من كائن : يمكن استخدام : باستخدام " Object الأسلوب" الثابت ، الذي يقوم بإرجاع صفيف ، كل عنصر من عناصره عبارة عن صفيف يحتوي ، كعنصر أول ، مفتاح ، وكقيمة ثانية - قيمة.

 var obj = { x: 1, y: 2, z: 3 }; var objEntries = Object.entries( obj ); console.log( objEntries ); // [["x", 1],["y", 2],["z", 3]] 

الآن لدينا تحت Object.fromEntries() أسلوب ثابت Object.fromEntries() ، والذي يسمح لنا بتحويل بنية مماثلة مرة أخرى إلى كائن.

 var entries = [["x", 1],["y", 2],["z", 3]]; var obj = Object.fromEntries( entries ); console.log( obj ); // {x: 1, y: 2, z: 3} 

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

 var obj = { x: 1, y: 2, z: 3 }; // [["x", 1],["y", 2],["z", 3]] var objEntries = Object.entries( obj ); // [["x", 1],["z", 3]] var filtered = objEntries.filter( ( [key, value] ) => value % 2 !== 0 //  ,     ); console.log( Object.fromEntries( filtered ) ); // {x: 1, z: 3} 

إذا تم استخدام Map : بنية البيانات لتخزين الأزواج : ، فسيتم تخزين البيانات الموجودة بها بالترتيب الذي تمت إضافته إليه. في نفس الوقت ، تشبه كيفية تخزين البيانات الصفيف الذي تم إرجاعه بواسطة الأسلوب Object.entries() . أسلوب Object.fromEntries() سهل الاستخدام Object.fromEntries() لتحويل بنيات بيانات Map إلى كائنات.

 var m = new Map([["x", 1],["y", 2],["z", 3]]); console.log( m ); // {"x" => 1, "y" => 2, "z" => 3} console.log( Object.fromEntries( m ) ); // {x: 1, y: 2, z: 3} 

→ الدعم



property الملكية العالمية globalThis


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

في JavaScript المستندة إلى المستعرض ، على سبيل المثال ، القيمة العامة this هي كائن window . يمكنك التحقق من ذلك باستخدام إنشاء console.log(this) في المستوى العلوي من ملف JavaScript (في السياق الخارجي) أو في وحدة التحكم JS في المستعرض.


الوصول إلى هذا في وحدة تحكم المستعرض

تشير القيمة العامة this في Node.js إلى كائن عمومي. داخل عامل الويب ، يشير إلى العامل نفسه. ومع ذلك ، فإن الحصول على this القيمة العالمية ليس بالأمر السهل. حقيقة الأمر هي أنه لا يمكنك الرجوع إلى this أي مكان. على سبيل المثال ، إذا حاولت القيام بذلك في مُنشئ الفصل ، اتضح أن this يشير إلى مثيل للفئة المقابلة.

في بعض البيئات ، يمكن استخدام this self للوصول إلى القيمة العالمية this . تلعب هذه الكلمة الأساسية نفس دور آليات الوصول إلى هذه القيمة في المتصفحات وفي Node.js وفي العاملين على الويب. باستخدام معرفة كيفية تسمية القيمة العامة this في بيئات مختلفة ، يمكنك إنشاء دالة تُرجع هذه القيمة:

 const getGlobalThis = () => { if (typeof self !== 'undefined') return self; if (typeof window !== 'undefined') return window; if (typeof global !== 'undefined') return global; if (typeof this !== 'undefined') return this; throw new Error('Unable to locate global `this`'); }; var globalThis = getGlobalThis(); 

أمامنا هو polyfill بدائية للحصول على this الكائن العالمية. اقرأ المزيد عن هذا هنا . جافا سكريبت لديها الآن الكلمة globalThis . إنه يوفر طريقة عالمية للوصول إلى القيمة العالمية this في بيئات مختلفة ولا يعتمد على موقع البرنامج الذي يتم الوصول إليه منه.

 var obj = { fn: function() {  console.log( 'this', this === obj ); // true  console.log( 'globalThis', globalThis === window ); // true } }; obj.fn(); 

→ الدعم



الفرز مستقر


لا يوفر معيار ECMAScript خوارزمية فرز صفيف محددة يجب أن تقوم محركات JavaScript بتطبيقها. يصف API المستخدمة فقط للفرز. نتيجة لذلك ، باستخدام محركات JS المختلفة ، قد يواجه المرء اختلافات في أداء عمليات الفرز وفي استقرار (استقرار) خوارزميات الفرز.

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

 var list = [  { name: 'Anna', age: 21 },  { name: 'Barbra', age: 25 },  { name: 'Zoe', age: 18 },  { name: 'Natasha', age: 25 } ]; //      age [  { name: 'Natasha', age: 25 }  { name: 'Barbra', age: 25 },  { name: 'Anna', age: 21 },  { name: 'Zoe', age: 18 }, ] 

هنا ، يتم فرز مصفوفة list التي تحتوي على الكائنات حسب الحقل age لهذه الكائنات. في صفيف list ، يوجد كائن به خاصية name مساوٍ Barbra قبل الكائن ذي خاصية name مساوية Natasha . نظرًا لأن القيم age لهذه الكائنات متساوية ، فيمكننا توقع أن تحتفظ هذه العناصر في الصفيف الذي تم الفرز بترتيب الترتيب السابق بالنسبة لبعضها البعض. ومع ذلك ، في الممارسة العملية لا يمكن توقع ذلك. بالضبط كيف سيتم تشكيل مجموعة مصنفة يعتمد كليا على محرك JS المستخدمة.

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

 //    [  { name: 'Barbra', age: 25 },  { name: 'Natasha', age: 25 }  { name: 'Anna', age: 21 },  { name: 'Zoe', age: 18 }, ] 

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

→ الدعم


  • Chrome: 70+
  • العقدة: 12+
  • فايرفوكس: 62+

API التدويل


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

elIntl.RelativeTimeFormat ()


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

لدى JS الآن Intl.RelativeTimeFormat(locale, config) ، والذي يسمح لك بإنشاء أنظمة تنسيق التاريخ والوقت لمختلف اللغات. على وجه الخصوص ، نحن نتحدث عن الكائنات التي لها طريقة .format(value, unit) ، والتي تتيح لك إنشاء طوابع زمنية مختلفة نسبيًا. يبدو مثل هذا:

 // español ( ) var rtfEspanol= new Intl.RelativeTimeFormat('es', {  numeric: 'auto' }); console.log( rtfEspanol.format( 5, 'day' ) ); // dentro de 5 días console.log( rtfEspanol.format( -5, 'day' ) ); // hace 5 días console.log( rtfEspanol.format( 15, 'minute' ) ); // dentro de 15 minutos 

→ الدعم



tIntl.ListFormat ()


يسمح Intl.ListFormat مُنشئ Intl.ListFormat بدمج عناصر القائمة باستخدام الكلمات and ( ) و ( ). عند إنشاء الكائن المقابل ، يتم تمرير المنشئ إلى اللغة والكائن مع المعلمات. يمكن أن تكون معلمة type هي conjunction disjunction unit . على سبيل المثال ، إذا كنا نرغب في دمج عناصر [apples, mangoes, bananas] باستخدام كائن apples, mangoes and bananas على سلسلة من apples, mangoes and bananas . إذا استخدمنا كائنًا مفصولًا ، فسنحصل على سلسلة من أشكال apples, mangoes or bananas .

يحتوي الكائن الذي تم إنشاؤه بواسطة مُنشئ Intl.ListFormat على طريقة .format(list) تجمع بين القوائم. النظر في مثال:

 // español ( ) var lfEspanol = new Intl.ListFormat('es', {  type: 'disjunction' }); var list = [ 'manzanas', 'mangos', 'plátanos' ]; console.log( lfEspanol.format( list ) ); // manzanas, mangos o plátanos 

→ الدعم



tIntl.Locale ()


عادة ما يكون مفهوم "المعيار الإقليمي" أكثر بكثير من مجرد اسم اللغة. قد يشمل ذلك نوع التقويم ، ومعلومات حول الدورات الزمنية المستخدمة ، وأسماء اللغات. يتم Intl.Locale(localeId, config) مُنشئ Intl.Locale(localeId, config) لإنشاء سلاسل Intl.Locale(localeId, config) منسقة بناءً على كائن config تم تمريره إليها.

Intl.Locale الكائن الذي تم إنشاؤه باستخدام Intl.Locale على جميع الإعدادات الإقليمية المحددة. أسلوب .toString() ينتج سلسلة قياسية إقليمية منسقة.

 const krLocale = new Intl.Locale( 'ko', {  script: 'Kore', region: 'KR',  hourCycle: 'h12', calendar: 'gregory' } ); console.log( krLocale.baseName ); // ko-Kore-KR console.log( krLocale.toString() ); // ko-Kore-KR-u-ca-gregory-hc-h12 

هنا يمكنك أن تقرأ عن المعرفات وعلامات اللغة في Unicode.

→ الدعم



PROMIS


اعتبارا من الآن ، JS لديه أساليب ثابتة Promise.all() و Promise.race() . تقوم طريقة Promise.all([...promises]) بإرجاع وعد تم حله بنجاح بعد حل كافة الوعود التي تم تمريرها إلى الطريقة كوسيطة. يتم رفض هذا الوعد في حالة رفض واحد على الأقل من الوعود المنقولة إليه. تُرجع طريقة Promise.race([...promises]) وعدًا ، يتم حله بعد حل أي من الوعود المنقولة إليه ، ويتم رفضه إذا تم رفض واحد على الأقل من هذه الوعود.

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

▍ طريقة Promise.allSettled ()


يقبل أسلوب Promise.allSettled() مجموعة من الوعود. الوعد الذي أعاده مسموح به بعد رفض أو رفض جميع الوعود. والنتيجة هي أن الوعد الذي تم إرجاعه بواسطة هذه الطريقة لا يحتاج إلى catch .

والحقيقة هي أن هذا الوعد دائما حلها بنجاح. يتلقى المربع then status value من كل وعد بالترتيب الذي تظهر به.

 var p1 = () => new Promise(  (resolve, reject) => setTimeout( () => resolve( 'val1' ), 2000 ) ); var p2 = () => new Promise(  (resolve, reject) => setTimeout( () => resolve( 'val2' ), 2000 ) ); var p3 = () => new Promise(  (resolve, reject) => setTimeout( () => reject( 'err3' ), 2000 ) ); var p = Promise.allSettled( [p1(), p2(), p3()] ).then(  ( values ) => console.log( values ) ); //  [ {status: "fulfilled", value: "val1"}  {status: "fulfilled", value: "val2"}  {status: "rejected", value: "err3"} ] 

→ الدعم



▍ طريقة Promise.any ()


Promise.any() طريقة Promise.any() طريقة Promise.race() ، لكن الوعد الذي تم إرجاعه Promise.race() لا ينفذ catch عندما يتم رفض أحد الوعود التي تم تمريرها إلى هذه الطريقة.

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

النتائج


في هذه المقالة ، نظرنا في بعض ابتكارات JavaScript التي تمت مناقشتها في مؤتمر Google I / O 2019 . نأمل أن تجد شيئًا ما مفيدًا لك.

أعزائي القراء! ما الذي تفتقده بشكل خاص في JavaScript؟

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


All Articles