JavaScript: apa yang akan kita lakukan selanjutnya tahun depan





Selamat siang teman!



Artikel ini berfokus pada kapabilitas JavaScript yang akan disajikan dalam versi baru spesifikasi (ECMAScript 2021, ES12).



Ini akan menjadi tentang yang berikut:



  • String.prototype.replaceAll ()
  • Promise.any ()
  • WeakRefs
  • Operator penugasan Boolean
  • Pemisah nomor




String.prototype.replaceAll ()



String.prototype.replaceAll () ( klausa Mathias Bynens ) memungkinkan Anda mengganti semua instance substring dalam string dengan nilai berbeda tanpa menggunakan regex global.



Pada contoh berikut, kami mengganti semua karakter "+" dengan koma dengan spasi menggunakan ekspresi reguler:



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


Pendekatan ini membutuhkan penggunaan ekspresi reguler. Namun, ekspresi reguler yang kompleks sering kali menjadi sumber kesalahan.



Ada pendekatan lain berdasarkan penggunaan metode String.prototype.split () dan Array.prototype.join ():



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


Pendekatan ini menghindari penggunaan ekspresi reguler, tetapi Anda harus membagi string menjadi beberapa bagian (kata) yang terpisah, mengubahnya menjadi array, lalu menggabungkan elemen array tersebut menjadi string baru.



String.prototype.replaceAll () memecahkan masalah ini dan menyediakan cara sederhana dan nyaman untuk mengganti substring secara global:



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


Perhatikan bahwa untuk menjaga konsistensi dengan API sebelumnya, perilaku String.prototype.replaceAll (searchValue, newValue) (searchValue adalah nilai pencarian, newValue adalah nilai baru) sama dengan String.prototype.replace (searchValue, newValue), kecuali yang berikut ini:



  • Jika nilai pencarian adalah string, maka replaceAll menggantikan semua kecocokan, dan hanya mengganti yang pertama
  • Jika nilai yang diinginkan adalah ekspresi reguler non-global, maka replace menggantikan kecocokan pertama, dan replaceAll melontarkan pengecualian untuk menghindari konflik antara tidak adanya tanda "g" dan nama metode (ganti semua - ganti semua [kecocokan])


Jika ekspresi reguler global digunakan sebagai nilai pencarian, maka replace dan replaceAll berperilaku sama.



Bagaimana jika kita memiliki baris dengan jumlah spasi yang berubah-ubah di awal, akhir baris, dan di antara kata?



const whiteSpaceHell = '          '


Dan kami ingin mengganti dua atau lebih spasi dengan satu. Bisakah replaceAll memecahkan masalah ini? Tidak.



Dengan String.prototype.trim () dan ganti dengan ekspresi reguler global, ini dilakukan seperti ini:



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


Promise.any ()



Promise.any () ( saran dari Mathias Bynens, Kevin Gibbons, dan Sergey Rubanov ) mengembalikan nilai janji yang pertama kali dipenuhi. Menolak semua janji yang diteruskan ke Promise.any () sebagai argumen (sebagai larik) akan memunculkan pengecualian "AggregateError".



AggregateError adalah subclass Error baru yang mengelompokkan error individual. Setiap instance AggregateError berisi referensi ke array dengan pengecualian.



Mari pertimbangkan sebuah contoh:



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
})()


Hasilnya akan menjadi nilai dari janji terselesaikan pertama.



Contoh dari kalimat:



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




Perhatikan bahwa Promise.race (), tidak seperti Promise.any (), mengembalikan nilai dari janji terselesaikan pertama, apakah dipenuhi atau ditolak.



WeakRefs



WeakRefs (referensi lemah) ( diusulkan oleh Dean Tribble, Mark Miller, Till Schneidereit, dll. ) Menyediakan dua fitur baru:



  • Membuat Referensi Lemah ke Objek Menggunakan Kelas WeakRef
  • Menjalankan finalisator khusus setelah pengumpulan sampah menggunakan kelas FinalizationRegistry


Singkatnya, WeakRef memungkinkan Anda membuat referensi lemah ke objek yang merupakan nilai properti objek lain, dan finalizer dapat digunakan, antara lain, untuk menghapus referensi ke objek yang "dibersihkan" oleh pengumpul sampah.



Teknik ini dapat berguna saat membuat fungsi menghafal (memoization) yang menggunakan cache bawaan untuk mencegah eksekusi fungsi berulang jika ada nilai terhitung untuk argumen yang diteruskan ke fungsi dalam cache (asalkan objek digunakan sebagai nilai properti objek cache dan risiko penghapusan selanjutnya) ...



Seperti yang Anda ingat, alasan kemunculan struktur seperti Map (tabel hash) dalam JavaScript, selain kecepatan yang lebih tinggi dalam mencari nilai dengan kunci, adalah karena hanya string atau karakter yang dapat menjadi kunci dari objek biasa. Peta, di sisi lain, memungkinkan Anda menggunakan tipe data apa pun sebagai kunci, termasuk objek.



Namun, masalah kebocoran memori segera muncul: menghapus objek yang merupakan kunci Peta tidak membuat objek tersebut tidak dapat dijangkau (mark-and-sweep), yang mencegah pengumpul sampah untuk menghancurkannya, membebaskan memori yang ditempati.



Dengan kata lain, objek yang digunakan sebagai kunci di Peta akan disimpan selamanya.



Struktur lain, WeakMap (dan WeakSet), diperkenalkan untuk mengatasi masalah ini. Perbedaan antara WeakMap dan Map adalah referensi ke objek utama di WeakMap lemah: menghapus objek semacam itu memungkinkan pengumpul sampah untuk mengalokasikan kembali memori yang dialokasikan untuknya.



Jadi, proposal ini mewakili tahap selanjutnya dalam pengembangan tabel hash di JavaScript. Objek sekarang dapat digunakan sebagai kunci dan sebagai nilai di objek lain tanpa risiko kebocoran memori.



Sekali lagi, saat membuat cache sebaris:



  • Jika tidak ada risiko kebocoran memori, gunakan Peta
  • Saat menggunakan objek utama yang dapat dihapus kemudian, gunakan WeakMap
  • Saat menggunakan objek nilai yang dapat dihapus kemudian, gunakan Map bersama dengan WeakRef


Contoh kasus terakhir dari proposal:



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


  • Konstruktor WeakRef mengambil argumen yang harus berupa objek dan mengembalikan referensi lemah ke sana
  • Metode deref dari instance WeakRef mengembalikan salah satu dari dua nilai:


Dalam kasus cache bawaan, finalizer dirancang untuk menyelesaikan proses pembersihan setelah objek nilai dihancurkan oleh pengumpul sampah, atau, lebih sederhananya, untuk menghapus referensi yang lemah ke objek semacam itu.



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


Baca lebih lanjut tentang finalis dan cara menggunakannya dalam proposal. Secara umum, finalizer sebaiknya hanya digunakan jika benar-benar diperlukan.



Operator penugasan Boolean



Operator penugasan Boolean ( proposal Justin Ridgewell dan Hemanth HM ) adalah kombinasi dari operator Boolean (&&, ||, ??) dan ekspresi penugasan.



Saat ini, JavaScript memiliki operator penetapan berikut:



=
 

+=
  

-=
  

/=
  

*=
  

&&=
   

||=
   

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

**=
    

%=
    

&=
   

|=
   

^=
    

<<=
    

>>=
    

>>>=
       

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


Klausa memungkinkan Anda untuk menggabungkan operator logika dan ekspresi penugasan:



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

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

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


Contoh dari sebuah kalimat:



//    
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' })


Pemisah nomor



Pemisah angka (saran Christophe Porteneuve ), atau lebih khusus lagi, pemisah angka dalam angka, memungkinkan Anda menambahkan garis bawah (_) di antara angka agar angka lebih mudah dibaca.



Contohnya:



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


Pemisah memecahkan masalah ini:



const num = 100_000_000 //  : 100 


Pemisah dapat digunakan di bagian bilangan bulat dan desimal dari sebuah angka:



const num = 1_000_000.123_456


Pemisah dapat digunakan tidak hanya dalam bilangan bulat dan bilangan floating point, tetapi juga dalam literal biner, heksadesimal, oktal, dan BigInt.



Perkembangan lebih lanjut dari pemisah angka menyiratkan kemungkinan penggunaan yang berguna dari beberapa pemisah dan pemisah berturut-turut yang muncul sebelum dan sesudah angka.



Ingin menguji atau memoles pengetahuan JavaScript Anda? Kemudian perhatikan lamaran saya yang luar biasa (Anda tidak bisa memuji diri sendiri ...).



Semoga Anda menemukan sesuatu yang menarik untuk diri Anda sendiri. Terima kasih atas perhatian Anda.



All Articles