JavaScript:来年の次の予定





良い一日、友達!



この記事では、新しいバージョンの仕様(ECMAScript 2021、ES12)で提供されるJavaScript機能に焦点を当てます



それは次のようになります:



  • String.prototype.replaceAll()
  • Promise.any()
  • WeakRefs
  • ブール割り当て演算子
  • 番号区切り




String.prototype.replaceAll()



String.prototype.replaceAll()(Mathias Bynens句)を使用すると、グローバルregexを使用せずに、文字列内のサブ文字列のすべてのインスタンスを異なる値に置き換えることができます。



次の例では、通常の式を使用して、すべての「+」文字をスペース付きのコンマに置き換えます。



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('+', ', ')
// , , 


以前のAPIとの一貫性を保つために、String.prototype.replaceAll(searchValue、newValue)(searchValueは検索値、newValueは新しい値)の動作は、次の点を除いてString.prototype.replace(searchValue、newValue)と同じであることに注意してください。



  • 検索値が文字列の場合、replaceAllはすべての一致を置き換え、最初の一致のみを置き換えます
  • 目的の値が非グローバル正規式の場合、replaceは最初の一致を置き換え、replaceAllは例外をスローして、「g」フラグがないこととメソッド名の競合を回避します(replace all-replace all [matches])


グローバル正規式がルックアップ値として使用されている場合、replaceとreplaceAllは同じように動作します。



行の最初、最後、および単語の間に任意の数のスペースがある行がある場合はどうなりますか?



const whiteSpaceHell = '          '


そして、2つ以上のスペースを1つに置き換えたいと思います。replaceAllはこの問題を解決できますか?番号。



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()に渡されたすべてのpromiseを引数として(配列として)拒否すると、「AggregateError」例外がスローされます。



AggregateErrorは、個々のエラーをグループ化する新しいErrorサブクラスです。各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の値になります。



文からの例:



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.any()とは異なり、Promise.race()は、実行されたか拒否されたかに関係なく、最初に解決されたpromiseの値を返すことに注意してください。



WeakRefs



WeakRefs(弱い参照)(Dean Tribble、Mark Miller、Till Schneidereitなどによって提案された)は、2つの新機能を提供します。



  • WeakRefクラスを使用したオブジェクトへの弱い参照の作成
  • FinalizationRegistryクラスを使用したガベージコレクション後にカスタムファイナライザーを実行する


つまり、WeakRefを使用すると、別のオブジェクトのプロパティの値であるオブジェクトへの弱い参照を作成できます。また、ファイナライザーを使用して、ガベージコレクターによって「クリーンアップ」されたオブジェクトへの参照を削除できます。



この手法は、組み込みキャッシュを使用して、キャッシュ内の関数に渡された引数の計算値がある場合に関数の繰り返し実行を防ぐ暗記関数(記憶)を作成するときに役立ちます(オブジェクトがキャッシュオブジェクトのプロパティの値として使用され、その後削除されるリスクがある場合) ..。



ご存知のように、JavaScriptでマップ(ハッシュテーブル)などの構造が表示される理由は、キーによる値の検索が高速であることに加えて、通常のオブジェクトのキーは文字列または文字のみであるためです。一方、マップを使用すると、オブジェクトを含め、任意のデータタイプをキーとして使用できます。



ただし、メモリリークの問題がすぐに発生しました。マップキーであるオブジェクトを削除しても、それらのオブジェクトに到達できなくなり(マークアンドスイープ)、ガベージコレクタがオブジェクトを破壊して、占有していたメモリを解放するのを防ぎました。



つまり、マップでキーとして使用されるオブジェクトは永久に保存されます。



この問題を解決するために、別の構造である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コンストラクターは、オブジェクトでなければならない引数を取り、それへの弱い参照を返します
  • WeakRefインスタンスのderefメソッドは、次の2つの値のいずれかを返します。


組み込みキャッシュの場合、ファイナライザーは、値オブジェクトがガベージコレクターによって破棄された後にクリーンアッププロセスを完了するように、またはより簡単に言えば、そのようなオブジェクトへの弱い参照を削除するように設計されています。



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);


ファイナライザーとその提案での使用方法の詳細をご覧ください。一般に、ファイナライザーは絶対に必要な場合にのみ使用してください。



ブール割り当て演算子



ブール割り当て演算子(JustinRidgewellの提案とHemanthHM)は、ブール演算子(&&、||、??)と割り当て式の組み合わせです。



現在、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' })


番号区切り



数字の区切り記号(Christophe Porteneuveの提案)、より正確には数字の数字の区切り記号を使用すると、数字の間に下線(_)を追加して、数字を読みやすくすることができます。



例えば:



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


セパレーターはこの問題を解決します:



const num = 100_000_000 //  : 100 


セパレータは、数値の整数部分と小数部分の両方で使用できます。



const num = 1_000_000.123_456


セパレータは、整数や浮動小数点数だけでなく、2進、16進、8進、BigIntの各リテラルでも使用できます。



番号セパレーターのさらなる開発は、番号の前後にいくつかの連続したセパレーターとセパレーターの有用な使用の可能性を意味します。



JavaScriptの知識をテストまたはブラッシュアップしたいとお考えですか?次に、私のすばらしいアプリケーションに注意を払ってください(自分を称賛することはできません...)。



あなたがあなた自身のために何か面白いものを見つけたことを願っています。清聴ありがとうございました。



All Articles