JavaScript: ما هو التالي بالنسبة لنا العام المقبل





يوم جيد ، أيها الأصدقاء!



تركز هذه المقالة على إمكانيات JavaScript التي سيتم تقديمها في الإصدار الجديد من المواصفات (ECMAScript 2021، ES12).



سيكون حول ما يلي:



  • String.prototype.replaceAll ()
  • Promise.any (مخرج)
  • ضعيف
  • عوامل التخصيص المنطقية
  • فواصل الأرقام




String.prototype.replaceAll ()



String.prototype.replaceAll () ( عبارة Mathias Bynens ) تسمح لك باستبدال جميع مثيلات سلسلة فرعية في سلسلة بقيمة مختلفة دون استخدام تعبير عادي.



في المثال التالي ، نستبدل جميع الأحرف "+" بفواصل بمسافة باستخدام تعبير عادي:



const strWithPlus = '++'
const strWithComma = strWithPlus.replace(/+/g, ', ')
// , , 


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



هناك طريقة أخرى تعتمد على استخدام طريقتي String.prototype.split () و Array.prototype.join ():



const strWithPlus = '++'
const strWithComma = strWithPlus.split('+').join(', ')
// , , 


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



String.prototype.replaceAll () يحل هذه المشاكل ويوفر طريقة بسيطة ومريحة لاستبدال السلاسل الفرعية بشكل عام:



const strWithPlus = '++'
const strWithComma = strWithPlus.replaceAll('+', ', ')
// , , 


لاحظ أنه من أجل الحفاظ على التناسق مع واجهات برمجة التطبيقات السابقة ، فإن سلوك String.prototype.replaceAll (searchValue ، newValue) (searchValue هو قيمة البحث ، newValue هي القيمة الجديدة) هو نفسه String.prototype.replace (searchValue ، newValue) ، باستثناء ما يلي:



  • إذا كانت قيمة البحث عبارة عن سلسلة ، فإن replaceAll يستبدل جميع التطابقات ، ويستبدل الأول فقط
  • إذا كانت القيمة المطلوبة تعبيرًا عاديًا غير عام ، فعندئذٍ يستبدل الاستبدال المطابقة الأولى ، ويؤدي replaceAll إلى استثناء لتجنب التعارض بين عدم وجود علامة "g" واسم الطريقة (استبدل الكل - استبدل جميع [التطابقات])


إذا تم استخدام تعبير عادي عام كقيمة بحث ، فحينئذٍ يتصرف الاستبدال والاستبدال الكل بنفس الطريقة.



ماذا لو كان لدينا خط به عدد عشوائي من المسافات في بداية السطر ونهايته وبين الكلمات؟



const whiteSpaceHell = '          '


ونريد استبدال مسافتين أو أكثر بواحد. هل يمكن أن يحل محل الكل حل هذه المشكلة؟ لا.



باستخدام String.prototype.trim () واستبداله بتعبير عادي عام ، يتم تنفيذ ذلك على النحو التالي:



const whiteSpaceNormal =
  whiteSpaceHell
    .trim()
    .replace(/\s{2,}/g, ' ')
    // \s{2,}     
    //   


Promise.any (مخرج)



Promise.any () ( اقتراح من Mathias Bynens و Kevin Gibbons و Sergey Rubanov ) يعيد قيمة الوعد الأول الذي تم الوفاء به. سيؤدي رفض جميع الوعود التي تم تمريرها إلى Promise.any () كوسيطة (كمصفوفة) إلى ظهور استثناء "AggregateError".



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



لنفكر في مثال:



const promise1 = new Promise((resolve, reject) => {
  const timer = setTimeout(() => {
    resolve('p1')
    clearTimeout(timer)
  }, ~~(Math.random() * 100))
}) // ~~ -   Math.floor()

const promise2 = new Promise((resolve, reject) => {
  const timer = setTimeout(() => {
    resolve('p2')
    clearTimeout(timer)
  }, ~~(Math.random() * 100))
})

;(async() => {
  const result = await Promise.any([promise1, promise2])
  console.log(result) // p1  p2
})()


ستكون النتيجة هي قيمة الوعد الأول المصمم.



مثال من الجملة:



Promise.any([
  fetch('https://v8.dev/').then(() => 'home'),
  fetch('https://v8.dev/blog').then(() => 'blog'),
  fetch('https://v8.dev/docs').then(() => 'docs')
]).then((first) => {
  //  ()   
  console.log(first);
  // → 'home'
}).catch((error) => {
  //    
  console.log(error);
})




لاحظ أن Promise.race () ، بخلاف Promise.any () ، يعرض قيمة الوعد الأول الذي تم حله ، سواء تم الوفاء به أو رفضه.



ضعيف



توفر WeakRefs (المراجع الضعيفة) ( التي اقترحها Dean Tribble و Mark Miller و Till Schneidereit وما إلى ذلك ) ميزتين جديدتين:



  • إنشاء مراجع ضعيفة لكائن باستخدام فئة WeakRef
  • تشغيل Finalizers المخصصة بعد جمع البيانات المهملة باستخدام فئة FinalizationRegistry


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



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



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



ومع ذلك ، سرعان ما ظهرت مشكلة تسرب الذاكرة: حذف الكائنات التي كانت مفاتيح الخريطة لم يجعل تلك الكائنات غير قابلة للوصول (علامة واكتساح) ، مما منع جامع القمامة من تدميرها ، وتحرير الذاكرة التي كانوا يحتلونها.



بمعنى آخر ، يتم حفظ الكائنات المستخدمة كمفاتيح في الخريطة إلى الأبد.



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



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



مرة أخرى ، عندما يتعلق الأمر بإنشاء ذاكرة تخزين مؤقت مضمنة:



  • إذا لم يكن هناك خطر حدوث تسرب للذاكرة ، فاستخدم الخريطة
  • عند استخدام العناصر الرئيسية التي يمكن حذفها لاحقًا ، استخدم WeakMap
  • عند استخدام كائنات القيمة التي يمكن إزالتها لاحقًا ، استخدم Map جنبًا إلى جنب مع WeakRef


مثال على الحالة الأخيرة من الاقتراح:



function makeWeakCached(f) {
  const cache = new Map()
  return key => {
    const ref = cache.get(key)
    if (ref) {
      //     
      const cached = ref.deref()
      if (cached !== undefined) return cached;
    }

    const fresh = f(key)
    //    ( )
    cache.set(key, new WeakRef(fresh))
    return fresh
  };
}

const getImageCached = makeWeakCached(getImage);


  • يأخذ مُنشئ WeakRef وسيطة يجب أن تكون كائنًا ويعيد مرجعًا ضعيفًا إليها
  • ترجع طريقة deref لمثيل WeakRef إحدى القيمتين:


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



function makeWeakCached(f) {
  const cache = new Map()
  //    -   
  const cleanup = new FinalizationRegistry(key => {
    const ref = cache.get(key)
    if (ref && !ref.deref()) cache.delete(key)
  })

  return key => {
    const ref = cache.get(key)
    if (ref) {
      const cached = ref.deref()
      if (cached !== undefined) return cached
    }

    const fresh = f(key)
    cache.set(key, new WeakRef(fresh))
    //      ( )
    cleanup.register(fresh, key)
    return fresh
  }
}

const getImageCached = makeWeakCached(getImage);


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



عوامل التخصيص المنطقية



عوامل التخصيص المنطقية ( اقتراح Justin Ridgewell و Hemanth HM ) هي مزيج من العوامل المنطقية (&&، ||، ؟؟) وتعبيرات المهام.



اعتبارًا من اليوم ، لدى JavaScript عوامل تشغيل المهام التالية:



=
 

+=
  

-=
  

/=
  

*=
  

&&=
   

||=
   

??=
      (null  undefined -  , 0, false,  '' -  )

**=
    

%=
    

&=
   

|=
   

^=
    

<<=
    

>>=
    

>>>=
       

  
[a, b] = [ 10, 20 ]
{a, b} = { a: 10, b: 20 }


يسمح لك هذا البند بدمج العوامل المنطقية وتعبيرات التخصيص:



a ||= b
// : a || (a = b)
//     ,   "a"  

a &&= b
// : a && (a = b)
//     ,   "a"  

a ??= b
// : a ?? (a = b)
//     ,   "a"   (null  undefined)


مثال من جملة:



//    
function example(opts) {
  //  ,    
  opts.foo = opts.foo ?? 'bar'

  //   ,     
  opts.baz ?? (opts.baz = 'qux')
}

example({ foo: 'foo' })

//    
function example(opts) {
  //     
  opts.foo ??= 'bar'

  //  ""   opts.baz
  opts.baz ??= 'qux';
}

example({ foo: 'foo' })


فواصل الأرقام



تسمح لك فواصل الأرقام ( اقتراح كريستوف بورتينوف ) ، أو بشكل أكثر دقة ، فواصل الأرقام بالأرقام ، بإضافة حرف تسطير أسفل السطر (_) بين الأرقام لجعل الأرقام أكثر قابلية للقراءة.



على سبيل المثال:



const num = 100000000
//     num? 1 ? 100 ? 10 ?


الفواصل تحل هذه المشكلة:



const num = 100_000_000 //  : 100 


يمكن استخدام الفواصل في كل من الأعداد الصحيحة والأجزاء العشرية للرقم:



const num = 1_000_000.123_456


يمكن استخدام الفواصل ليس فقط على الأعداد الصحيحة وأرقام الفاصلة العائمة ، ولكن أيضًا على القيم الثنائية ، والسداسية العشرية ، والثمانية ، و BigInt.



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



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



أتمنى أن تجد شيئًا ممتعًا لنفسك. شكرآ لك على أهتمامك.



All Articles