Fitur JavaScript yang kurang dikenal

JavaScript sering disebut bahasa paling sederhana untuk pemula, dalam pemrograman yang merupakan yang paling sulit untuk dicapai penguasaannya. Penulis materi, terjemahan yang kami terbitkan, mengatakan bahwa ia tidak bisa tidak setuju dengan pernyataan ini. Masalahnya adalah bahwa JS adalah bahasa yang sangat tua dan sangat fleksibel. Ini penuh dengan konstruksi sintaksis misterius dan fitur usang yang masih didukungnya.

gambar

Hari ini kita akan berbicara tentang fitur dan opsi JavaScript yang kurang dikenal untuk aplikasi praktisnya.

JavaScript selalu merupakan sesuatu yang baru


Saya telah bekerja dengan JavaScript selama bertahun-tahun dan saya terus-menerus menemukan sesuatu yang tidak pernah saya duga ada. Di sini saya mencoba untuk membuat daftar fitur-fitur bahasa yang kurang dikenal yang serupa. Dalam mode ketat, beberapa dari mereka tidak akan bekerja, tetapi dalam mode normal mereka benar-benar contoh kode JS. Perlu dicatat bahwa saya tidak menyarankan untuk menyarankan pembaca untuk mengambil semua ini ke dalam layanan. Meskipun apa yang akan saya bicarakan tampaknya sangat menarik bagi Anda, Anda dapat mulai menggunakan semua ini jika Anda bekerja dalam tim dan, secara sederhana, mengejutkan rekan kerja Anda.

→ Kode yang akan kita bahas di sini dapat ditemukan di sini.

Harap dicatat bahwa saya tidak memasukkan hal-hal seperti meningkatkan variabel, penutupan, objek proxy, pewarisan prototipe, async / menunggu, generator, dan sejenisnya. Meskipun fitur-fitur bahasa ini dapat dikaitkan dengan sulit untuk dipahami, mereka tidak dikenal.

Operator batal


JavaScript memiliki operator void unary. Anda mungkin menemukan itu dalam bentuk void(0) atau void 0 . Satu-satunya tujuan adalah untuk menghitung ekspresi ke kanan dan mengembalikan yang undefined . 0 sini digunakan hanya karena itu adalah kebiasaan, meskipun ini tidak perlu, dan di sini Anda dapat menggunakan ekspresi yang valid. Benar, operator ini bagaimanapun akan kembali undefined .

 //  void void 0                  // undefined void (0)                // undefined void 'abc'              // undefined void {}                 // undefined void (1 === 1)          // undefined void (1 !== 1)          // undefined void anyfunction()      // undefined 

Mengapa menambahkan kata kunci khusus ke bahasa yang berfungsi mengembalikan undefined , jika Anda bisa menggunakan nilai standar undefined ? Bukan, ada redundansi?

Ternyata, sebelum munculnya standar ES5 di sebagian besar browser, nilai standar undefined dapat diberi nilai baru. Katakanlah Anda berhasil menjalankan perintah ini: undefined = "abc" . Akibatnya, nilai yang undefined mungkin tidak seperti yang seharusnya. Pada masa itu, penggunaan void memungkinkan kami untuk memastikan kepercayaan dalam penggunaan yang sebenarnya undefined .

Kurung saat memanggil konstruktor adalah opsional


Tanda kurung yang ditambahkan setelah nama kelas, memanggil konstruktor, sepenuhnya opsional (kecuali konstruktor perlu memberikan argumen).

Dalam contoh berikut, ada atau tidaknya tanda kurung tidak memengaruhi operasi program yang benar.

 //     const date = new Date() const month = new Date().getMonth() const myInstance = new MyClass() //     const date = new Date const month = (new Date).getMonth() const myInstance = new MyClass 

Kurung tidak dapat digunakan dengan IIFE


Sintaks IIFE selalu tampak aneh bagi saya. Mengapa ada semua tanda kurung ini?

Ternyata, tanda kurung hanya diperlukan untuk memberi tahu parser JavaScript bahwa beberapa kode adalah ekspresi fungsional, dan bukan upaya yang salah untuk mendeklarasikan fungsi. Mengetahui fakta ini memungkinkan kita untuk memahami bahwa ada banyak cara untuk menyingkirkan tanda kurung di mana IIFE terlampir, dan pada saat yang sama menulis kode kerja.

 // IIFE (function () { console.log('Normal IIFE called') })() // Normal IIFE called void function () { console.log('Cool IIFE called') }() // Cool IIFE called 

Di sini, operator void memberi tahu parser bahwa kode yang mengikutinya adalah ekspresi fungsional. Ini memungkinkan untuk menyingkirkan tanda kurung di sekitar deklarasi fungsi. Dan omong-omong, di sini Anda dapat menggunakan operator unary ( void , + , ! , - , dan sebagainya), dan kodenya akan tetap berfungsi. Bukankah itu luar biasa?

Namun, jika Anda seorang pembaca yang penuh perhatian, maka Anda mungkin bertanya-tanya bahwa operator yang tidak waspada mempengaruhi hasil yang dikembalikan dari IIFE. Padahal, apa adanya. Tetapi hal baiknya adalah jika Anda membutuhkan hasil IIFE, yang Anda, misalnya, simpan dalam variabel, maka Anda tidak perlu tanda kurung di sekitar IIFE. Berikut ini sebuah contoh.

 // IIFE,    let result = (function () { // ... -  return 'Victor Sully' })() console.log(result) // Victor Sully let result1 = function () { // ... -  return 'Nathan Drake' }() console.log(result1) // Nathan Drake 

Kawat gigi di sekitar IIFE pertama hanya meningkatkan keterbacaan kode tanpa mempengaruhi operasinya.

Jika Anda ingin lebih memahami IIFE, lihat materi ini .

Konstruksi dengan


Tahukah Anda bahwa JavaScript memiliki konstruk yang mendukung blok ekspresi? Ini terlihat seperti ini:

 with (object)  statement //       with (object) {  statement  statement  ... } 

Konstruk with menambahkan semua properti objek yang diteruskan ke dalamnya dalam rantai lingkup yang digunakan saat menjalankan perintah.

 //    with const person = { firstname: 'Nathan', lastname: 'Drake', age: 29 } with (person) { console.log(`${firstname} ${lastname} is ${age} years old`) } // Nathan Drake is 29 years old 

with mungkin tampak seperti alat yang hebat. Sepertinya ini bahkan lebih baik daripada fitur baru JS untuk penghancuran objek , tetapi kenyataannya tidak.

Konstruksi with sudah usang dan tidak direkomendasikan untuk digunakan. Dalam mode ketat, penggunaannya dilarang. Ternyata with blok menyebabkan masalah kinerja dan keamanan.

Konstruktor fungsi


Menggunakan kata kunci function bukan satu-satunya cara untuk mendefinisikan fungsi baru. Anda dapat menetapkan fungsi secara dinamis menggunakan Function constructor dan operator new . Ini tampilannya.

 //  Function const multiply = new Function('x', 'y', 'return x*y') multiply(2,3) // 6 

Argumen terakhir yang diteruskan ke konstruktor adalah string dengan kode fungsi. Dua argumen lain adalah parameter fungsi.

Sangat menarik untuk dicatat bahwa Function constructor adalah "induk" dari semua konstruktor dalam JavaScript. Bahkan konstruktor Object adalah Konstruktor Function . Dan konstruktor Function asli juga Function . Akibatnya, panggilan dari objek object.constructor.constructor... dibuat untuk objek JS apa pun dalam jumlah yang cukup akan mengembalikan Function constructor sebagai hasilnya.

Properti Fitur


Kita semua tahu bahwa fungsi dalam JavaScript adalah objek kelas satu. Karena itu, tidak ada yang menghentikan kita dari menambahkan properti baru ke fungsi. Ini sangat normal, tetapi ini jarang digunakan.

Kapan ini dibutuhkan?

Bahkan, ada beberapa situasi di mana kemampuan fitur ini mungkin berguna. Pertimbangkan mereka.

▍ Fitur Kustom


Misalkan kita memiliki fungsi greet() . Kami membutuhkannya untuk menampilkan pesan sambutan yang berbeda tergantung pada pengaturan regional yang digunakan. Pengaturan ini dapat disimpan dalam variabel eksternal ke fungsi. Selain itu, fungsi tersebut mungkin memiliki properti yang mendefinisikan pengaturan ini, khususnya, pengaturan bahasa pengguna. Kami akan menggunakan pendekatan kedua.

 //  ,   function greet () { if (greet.locale === 'fr') {   console.log('Bonjour!') } else if (greet.locale === 'es') {   console.log('Hola!') } else {   console.log('Hello!') } } greet() // Hello! greet.locale = 'fr' greet() // Bonjour! 

▍Fungsi dengan variabel statis


Berikut adalah contoh serupa lainnya. Misalkan kita perlu mengimplementasikan generator tertentu yang menghasilkan urutan nomor yang dipesan. Biasanya dalam situasi seperti itu, untuk menyimpan informasi tentang nomor yang dihasilkan terakhir, variabel penghitung statis di kelas atau IIFE digunakan. Dengan pendekatan ini, kami membatasi akses ke konter dan mencegah polusi ruang lingkup global dengan variabel tambahan.

Tetapi bagaimana jika kita membutuhkan fleksibilitas, jika kita perlu membaca atau bahkan memodifikasi nilai penghitung seperti itu dan tidak menyumbat ruang lingkup global?

Tentu saja, Anda bisa membuat kelas dengan variabel yang sesuai dan dengan metode yang memungkinkan Anda untuk bekerja dengannya. Atau Anda tidak dapat repot-repot dengan hal-hal seperti itu dan hanya menggunakan properti fungsi.

 //  ,   function generateNumber () { if (!generateNumber.counter) {   generateNumber.counter = 0 } return ++generateNumber.counter } console.log(generateNumber()) // 1 console.log(generateNumber()) // 2 console.log('current counter value: ', generateNumber.counter) // current counter value: 2 generateNumber.counter = 10 console.log('current counter value: ', generateNumber.counter) // current counter value: 10 console.log(generateNumber()) // 11 

Properti objek argumen


Saya yakin sebagian besar dari Anda tahu bahwa fungsi memiliki objek arguments . Ini adalah objek mirip array yang dapat diakses dalam semua fungsi (dengan pengecualian fungsi panah, yang tidak memiliki objek arguments sendiri). Ini berisi daftar argumen yang diteruskan ke fungsi saat dipanggil. Selain itu, ia memiliki beberapa properti menarik:

  • arguments.callee berisi tautan ke fungsi saat ini.
  • arguments.caller berisi referensi ke fungsi yang disebut fungsi saat ini.

Pertimbangkan sebuah contoh.

 //  callee  caller  arguments const myFunction = function () { console.log('Current function: ', arguments.callee.name) console.log('Invoked by function: ', arguments.callee.caller.name) } void function main () { myFunction() } () // Current function: myFunction // Invoked by function: main 

Standar ES5 melarang penggunaan properti callee dan caller dalam mode ketat, tetapi mereka masih banyak ditemukan di banyak teks program yang dikompilasi JavaScript, misalnya, di perpustakaan. Karena itu, berguna untuk mengetahui tentang mereka.

Literal Templat Tagged


Tentunya Anda, jika Anda ada hubungannya dengan pemrograman JavaScript, telah mendengar tentang templat literal . Templat literal adalah salah satu dari banyak inovasi hebat dari standar ES6. Namun, apakah Anda tahu tentang literal templat yang ditandai?

 //    `Hello ${username}!` //    myTag`Hello ${username}!` 

Literal templat yang ditandai memungkinkan pengembang untuk mengontrol bagaimana literal templat berubah menjadi string. Ini dilakukan dengan menggunakan tag khusus. Tag hanyalah nama fungsi pengurai yang menerima larik string dan nilai yang ditafsirkan oleh pola string. Saat menggunakan fungsi tag, diharapkan akan mengembalikan string yang sudah selesai.

Dalam contoh berikut, tag kami, highlight , menginterpretasikan data dari templat literal dan menyematkan data ini dalam baris yang sudah jadi, menempatkannya dalam tag <mark> HTML untuk memilihnya ketika teks tersebut ditampilkan pada halaman web.

 //    function highlight(strings, ...values) { //  i -      let result = '' strings.forEach((str, i) => {   result += str   if (values[i]) {     result += `<mark>${values[i]}</mark>`   } }) return result } const author = 'Henry Avery' const statement = `I am a man of fortune & I must seek my fortune` const quote = highlight`${author} once said, ${statement}` // <mark>Henry Avery</mark> once said, <mark>I am a man of fortune // & I must seek my fortune</mark> 

Cara menarik untuk menggunakan fitur ini dapat ditemukan di banyak perpustakaan. Berikut ini beberapa contohnya:

  • komponen gaya - untuk digunakan dalam aplikasi Bereaksi.
  • es2015-i18n-tag - untuk terjemahan dan internasionalisasi proyek.
  • chalk - untuk menampilkan pesan multi-warna ke konsol.

Getters and Setters di ES5


Objek JavaScript, sebagian besar, cukup sederhana. Misalkan kita memiliki objek user , dan kami mencoba mengakses properti age menggunakan konstruk user.age . Dengan pendekatan ini, jika properti ini didefinisikan, kami akan mendapatkan nilainya, dan jika tidak didefinisikan, kami akan undefined . Semuanya sangat sederhana.

Tetapi bekerja dengan properti tidak harus begitu primitif sama sekali. Objek JS menerapkan konsep getter dan setter. Alih-alih langsung mengembalikan nilai beberapa properti objek, kita dapat menulis fungsi pengambil kita sendiri, yang mengembalikan apa yang kita anggap perlu. Hal yang sama berlaku untuk menulis nilai baru ke properti menggunakan fungsi setter.

Getters dan setter memungkinkan Anda untuk menerapkan skema canggih untuk bekerja dengan properti. Saat membaca atau menulis properti, Anda dapat menggunakan konsep bidang virtual, Anda dapat memeriksa nilai-nilai bidang, dan ketika menulis atau membaca, beberapa efek samping yang bermanfaat dapat terjadi.

 //    const user = { firstName: 'Nathan', lastName: 'Drake', // fullname -    get fullName() {   return this.firstName + ' ' + this.lastName }, //      set age(value) {   if (isNaN(value)) throw Error('Age has to be a number')   this._age = Number(value) }, get age() {   return this._age } } console.log(user.fullName) // Nathan Drake user.firstName = 'Francis' console.log(user.fullName) // Francis Drake user.age = '29' console.log(user.age) // 29 // user.age = 'invalid text' // Error: Age has to be a number 

Getters dan setter bukan inovasi standar ES5. Mereka selalu hadir dalam bahasa tersebut. Dalam ES5, hanya alat sintaks yang nyaman telah ditambahkan untuk bekerja dengannya. Detail tentang getter dan setter dapat ditemukan di sini .

Contoh penggunaan getter termasuk pustaka Node.js Colors yang populer.

Pustaka ini memperluas kelas String dan menambahkan banyak metode pengambil untuk itu. Ini memungkinkan Anda untuk mengkonversi string ke versi “berwarna” sehingga string ini kemudian dapat digunakan untuk logging. Ini dilakukan dengan bekerja dengan properti string.

Operator koma


JS memiliki operator koma. Ini memungkinkan Anda untuk menulis beberapa ekspresi dalam satu baris, dipisahkan oleh koma, dan mengembalikan hasil evaluasi dari ekspresi terakhir. Seperti apa desainnya.

 let result = expression1, expression2,... expressionN 

Di sini, nilai semua ekspresi akan dihitung, setelah itu nilai ekspresiN akan masuk ke dalam variabel result .

Ada kemungkinan bahwa Anda telah menggunakan operator koma for loop.

 for (var a = 0, b = 10; a <= 10; a++, b--) 

Terkadang operator ini sangat berguna ketika Anda perlu menulis banyak ekspresi pada baris yang sama.

 function getNextValue() {   return counter++, console.log(counter), counter } 

Ini bisa berguna saat mendesain fungsi panah kecil.

 const getSquare = x => (console.log (x), x * x) 

Operator plus


Jika Anda perlu dengan cepat mengubah string menjadi angka, operator plus berguna bagi Anda. Dia mampu bekerja dengan berbagai angka, dan tidak hanya, sepertinya, dengan yang positif. Kita berbicara tentang angka negatif, oktal, heksadesimal, dan angka dalam notasi eksponensial. Selain itu, ia dapat mengubah objek Date dan objek perpustakaan Moment.js menjadi cap waktu.

 //  "" +'9.11'          // 9.11 +'-4'            // -4 +'0xFF'          // 255 +true            // 1 +'123e-5'        // 0.00123 +false           // 0 +null            // 0 +'Infinity'      // Infinity +'1,234'         // NaN +new Date      // 1542975502981 ( ) +momentObject    // 1542975502981 ( ) 

Tanda seru ganda


Perlu dicatat bahwa apa yang kadang-kadang disebut "operator tanda seru ganda" (Bang Bang atau Double Bang) sebenarnya bukan operator. Ini adalah operator NOT logis, atau operator negasi logis yang terlihat seperti tanda seru diulang dua kali. Titik seru ganda baik karena memungkinkan Anda untuk mengubah ekspresi apa pun menjadi nilai boolean. Jika ekspresi, dari sudut pandang JS, benar - setelah memprosesnya dengan tanda seru ganda, true akan dikembalikan. Jika tidak, false akan dikembalikan.

 //     !!null            // false !!undefined       // false !!false           // false !!true            // true !!""              // false !!"string"        // true !!0               // false !!1               // true !!{}              // true !![]              // true 

Operator negasi bitwise


Mari kita hadapi itu: tidak ada yang peduli dengan operator bitwise. Saya tidak berbicara tentang menggunakannya. Namun, operator negasi bitwise dapat digunakan dalam banyak situasi.

Ketika operator ini diterapkan ke angka, itu mengubahnya sebagai berikut: dari nomor N ternyata -(N+1) . Ungkapan seperti itu memberi 0 jika N adalah -1 .

Fitur ini dapat digunakan dengan metode indexOf() ketika digunakan untuk memeriksa keberadaan elemen dalam array atau string, karena metode ini, tidak menemukan elemen, mengembalikan -1 .

 //      indexOf let username = "Nathan Drake" if (~username.indexOf("Drake")) { console.log('Access denied') } else { console.log('Access granted') } 

Perlu dicatat bahwa dalam standar ES6 dan ES7, masing-masing, untuk string dan array, metode includes() telah muncul. Jelas jauh lebih nyaman untuk menentukan keberadaan elemen daripada menggunakan operator negasi bitwise dan indexOf() .

Blok bernama


JavaScript memiliki konsep label, yang dengannya Anda dapat menetapkan nama (label) ke loop. Anda kemudian dapat menggunakan label ini untuk merujuk ke loop yang sesuai saat menerapkan pernyataan break atau continue . Label juga dapat ditugaskan untuk blok kode biasa.

Loop berlabel berguna saat bekerja dengan loop bersarang. Tetapi mereka juga dapat digunakan untuk mengatur kode dengan mudah di blok atau saat membuat blok di mana kode dapat terputus.

 //    declarationBlock: { //       //     var i, j } forLoop1: //     - "forLoop1" for (i = 0; i < 3; i++) {       forLoop2: //     -  "forLoop2"  for (j = 0; j < 3; j++) {       if (i === 1 && j === 1) {        continue forLoop1     }     console.log('i = ' + i + ', j = ' + j)  } } /* i = 0, j = 0 i = 0, j = 1 i = 0, j = 2 i = 1, j = 0 i = 2, j = 0 i = 2, j = 1 i = 2, j = 2 */ //      loopBlock4: { console.log('I will print') break loopBlock4 console.log('I will not print') } // I will print 

Perhatikan bahwa, tidak seperti beberapa bahasa lain, tidak ada goto di JS. Akibatnya, label hanya digunakan dengan pernyataan break dan continue .

Ringkasan


Pada artikel ini, kita berbicara tentang fitur JavaScript yang kurang dikenal, pengetahuan yang berguna bagi setiap programmer JS, setidaknya untuk siap untuk memenuhi sesuatu yang tidak biasa dalam kode orang lain. Jika topik "JS tidak dikenal" menarik bagi Anda, Anda dapat melihat publikasi kami ini.

Pembaca yang budiman! Jika Anda tahu tentang beberapa fitur JS yang tidak banyak diketahui dan melihat opsi untuk aplikasi praktisnya, silakan beri tahu kami.

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


All Articles