
Ketika saya membaca artikel lain tentang fitur yang sedikit diketahui dari bahasa JavaScript dan diam-diam kencing beberapa solusi gila di konsol browser, saya sering mengatakan di kepala saya bahwa, yah, itu tentu tidak begitu pada prod!! Lagipula, bahasa tersebut telah lama mengakuisisi komunitas besar dan memiliki cakupan pengembangan industri yang mengejutkan. Jika demikian, lalu mengapa kita sering lupa tentang kemampuannya untuk dipahami oleh semua orang dan secara harfiah mempromosikan semua konstruksi yang spesifik dan "berkesan" ini? Buat saja Jelas!
Alasan pada topik
Anda dapat melewati graphomania ini.
Jika kita berbicara tentang pengembangan industri, dalam sebagian besar kasus, persyaratan untuk kode yang akan didukung bahkan lebih penting daripada menyelesaikan tugas yang ditimbulkan oleh bisnis. Bagi banyak orang, ini jelas, bagi sebagian orang - sebagian (tentu saja, D'Artagnans langka juga ditemukan). Semakin jelas kode kita, semakin sedikit risiko untuk sampai ke rak berdebu, dan bagi kita dan penerus kita mendapatkan masalah dengan sistem saraf.
Bukan rahasia lagi bahwa JavaScript luar biasa dalam fleksibilitasnya, yang merupakan kebajikan terbesar dan kutukan yang menjengkelkan. Jalur pengembang JavaScript sangat panjang dan sangat menarik: kami menyerap buku demi buku, artikel demi artikel, dan mendapatkan pengalaman unik, tetapi terkadang itu benar-benar spesifik bahasa. Distribusi bahasa yang terluas dan pada saat yang sama sejumlah besar akumulasi dan pemberian yang tidak jelas berkontribusi pada pembentukan dua front: mereka yang hampir mengidolakan bahasa ini, dan mereka yang melihatnya sebagai bebek hak yang canggung dan bergoyang.
Dan semua akan baik-baik saja, tetapi seringkali perwakilan dari kedua front bekerja pada proyek yang sama. Dan yang biasa, semua praktik yang diterima adalah kesalahpahaman (keengganan untuk memahami dan bahkan mengabaikan) kode masing-masing. Dan faktanya, "Saya punya pengembang Java, dan bukan ini milik Anda!" . Pengikut Javascript sendiri menambahkan bahan bakar ke api, mengatakan "tidak ada yang benar-benar tahu JavaScript!" ya "Saya bisa menulisnya dalam satu baris di js!" . Saya mengaku bahwa saya sendiri menyalahgunakan pemrograman abnormal di waktu luang saya ...
Anda mulai merasakan masalah ini ketika Anda menggantikan posisi marginal dan mendapatkan pengalaman bekerja dengan orang-orang dan kode mereka di kedua sisi barikade. Perencanaan dan rapat lainnya lebih produktif ketika semua pengembang memahami satu sama lain, tidak hanya di tingkat lini bisnis, tetapi setidaknya sedikit di tingkat implementasi mereka. Faktor bass yang terkenal memiliki dampak yang lebih kecil pada proyek, ketika dalam hal penyakit front-ender tunggal, anggota tim lainnya tidak meremehkan untuk memperbaiki beberapa baris file .js . Proses berbagi pengetahuan di dalam tim dan di luar menjadi lebih transparan bagi semua orang ketika semua orang memiliki gambaran yang lebih rinci. Baik dan semuanya dalam nada yang sama.
Saya tidak mendesak siapa pun untuk "full glass" atau "T-shape" (bagaimana mengatakannya sekarang?), Tapi mengapa kita tidak sedikit menaikkan tirai ini, jika hanya dari komunitas JavaScript? Untuk melakukan ini, cukup dengan membawa sedikit kejelasan kode kita, menggunakan fleksibilitas bahasa untuk tidak pamer, tetapi untuk memahami kita.
Tumbuh dan mengambil tanggung jawab
Untuk bagiannya, JavaScript telah lama menyadari perannya, bukan sebagai bahasa untuk interaktivitas halaman Internet dan "menempelkan" sumber daya mereka, tetapi sebagai alat yang kuat dan cukup untuk membuat lintas-platform yang lengkap dan aplikasi yang seringkali sangat skalabel.
Awalnya dirancang untuk perancang web, "bahasa pemrograman yang paling banyak disalahpahami" ini telah lama menginjak air, meskipun popularitas dan relevansinya berkembang pesat. Selama 13-14 tahun sebelum edisi ECMAScript 5.1, sulit untuk mengingat setiap perubahan penting dalam standar atau memahami vektor perkembangannya. Pada saat itu, komunitasnya memberikan kontribusi besar pada pembentukan ekosistem bahasa: Prototipe, jQuery, MooTools, dll. Setelah menerima umpan balik ini dari para pengembang, JavaScript melakukan pekerjaan signifikan pada bug: rilis ES6 6-tahun yang keras pada tahun 2015 dan sekarang rilis tahunan ECMAScript, berkat komite TC39 yang mendesain ulang proses memperkenalkan fitur-fitur baru ke dalam spesifikasi.
Nah, ketika aplikasi kita menjadi cukup besar, model OOP prototipe untuk menggambarkan tipe pengguna tidak lagi dibenarkan karena pendekatan yang tidak biasa. Baik serius, ada apa?
function Animal() { } function Rabbit() {} Rabbit.prototype = Object.create(Animal.prototype); Rabbit.prototype.constructor = Rabbit;
Kelas tidak muncul dalam bahasa, tetapi sintaksisnya muncul. Dan kode tersebut telah tersedia untuk penganut paradigma tradisional yang berorientasi kelas:
class Animal { constructor() { } } class Rabbit extends Animal {}
Sekarang pada tahap kandidat untuk rilis adalah bidang pribadi kelas. Sulit dipercaya bahwa cepat atau lambat kita akan berhenti saling menertawakan dengan kesepakatan tentang penamaan properti pribadi melalui garis bawah.
Pada saat yang sama, dalam bahasa di mana fungsi adalah objek orde pertama dan peristiwa konstan terjadi, itu cukup umum:
let that = this; setTimeout(function() { that.n += 1; }, 1000);
Dan kemudian penjelasan tentang konteks ini dan penutupan dalam JavaScript dimulai, yang membuat takut setiap pengembang eksternal kedua. Tetapi dalam banyak kasus, bahasa menghindari kejutan yang tidak perlu dengan secara eksplisit menggunakan Function.prototype.bind atau bahkan lebih:
setTimeout(() => this.n += 1, 1000);
Kami juga punya fungsi panah, dan ini benar-benar fungsi, bukan antarmuka fungsional (ya, Java?). Bersama-sama dengan serangkaian metode yang diperluas untuk bekerja dengan array, mereka juga membantu untuk menulis garis perhitungan deklaratif yang biasa:
[-1, 2, -3, 4] .filter(x => x > 0) .map(x => Math.pow(2, x)) .reduce((s, x) => s + x, 0);
Bahasa dengan tepat menganggap dirinya multi-paradigmatik. Tapi di sini adalah contoh sederhana tentang tanda tangan beberapa fungsi:
function ping(host, count) { count = count || 5; }
Pertama, seseorang yang lewat akan mengajukan pertanyaan yang mengatakan bahwa mungkin suatu fungsi hanya dapat mengambil argumen pertama, dan kemudian mengatakan apa sih dalam kasus ini, menghitung menjadi Boolean! Memang, fungsi memiliki dua kegunaan: dengan menghitung dan tanpa. Tetapi ini sama sekali tidak jelas: Anda harus melihat implementasinya dan mengerti. Menggunakan JSDoc dapat membantu, tetapi ini bukan praktik yang umum. Dan di sini JavaScript maju, menambahkan dukungan bukan untuk kelebihan beban, tetapi setidaknya untuk parameter default:
function ping(host, count = 5) { }
Meringkas, JavaScript mendapat sejumlah besar hal-hal yang akrab: generator, iterator, Kumpulan koleksi dan kamus Peta , array yang diketik, dan bahkan ekspresi reguler mulai menyenangkan lihat di belakang dukungan! Bahasa melakukan segalanya agar cocok untuk banyak hal dan menjadi ramah bagi semua orang.
Jalur yang menguntungkan ke yang jelas
Bahasa itu sendiri sudah pasti dilakukan dengan baik, dan sulit untuk membantahnya! Tapi apa yang salah dengan kita? Mengapa kita terus-menerus mengingatkan seluruh dunia bahwa JavaScript berbeda? Mari kita lihat contoh-contoh dari beberapa teknik yang banyak digunakan dan bertanya tentang kesesuaian mereka.
Ketik casting
Ya, JavaScript memiliki sistem tipe dinamis dan lemah dan memungkinkan Anda untuk melakukan operasi pada apa pun, secara implisit melakukan transformasi untuk kami. Namun seringkali, casting eksplisit masih diperlukan bagi kami, dan berikut ini dapat diamati:
let bool = !!(expr); let numb = +(expr); let str = ''+(expr);
Trik ini diketahui oleh setiap pengembang JavaScript dan mereka termotivasi oleh fakta bahwa mereka mengatakan bahwa Anda dapat "dengan cepat" mengubah sesuatu menjadi sesuatu: kecepatan berarti catatan pendek. Bisakah itu juga menulis false segera sebagai ! 1 ? Jika pengembang sangat khawatir dengan karakter yang dapat dicetak, maka dalam IDE favoritnya Anda dapat dengan mudah mengonfigurasi templat langsung yang diperlukan atau melengkapi otomatis. Dan jika - untuk ukuran kode yang diterbitkan, maka kita selalu menjalankannya melalui obfuscator, siapa yang tahu lebih baik dari kita bagaimana cara merendahkan semua ini. Kenapa tidak:
let bool = Boolean(expr); let numb = Number(expr); let str = String(expr);
Hasilnya sama, hanya jelas untuk semua orang.
Untuk konversi string, kita harusString , tetapi untuk yang numerik ada valueOf yang menarik, yang juga bisa diganti. Contoh klasik yang memperkenalkan "belum tahu" ke dalam keadaan pingsan:
let timestamp = +new Date;
Tetapi Date memang memiliki metode getTime yang dikenal, mari kita gunakan:
let timestamp = (new Date()).getTime();
atau fungsi siap pakai:
let timestamp = Date.now();
Sama sekali tidak perlu mengeksploitasi konversi tipe implisit.
Operator logis
Perhatian khusus diberikan kepada operator logis AND (&&) dan OR (||), yang tidak cukup logis dalam JavaScript: mereka menerima dan mengembalikan nilai dari jenis apa pun. Kami tidak akan masuk ke detail operasi kalkulator ekspresi logis , kami akan mempertimbangkan contoh. Opsi yang disajikan sebelumnya dengan fungsi:
function ping(host, count) { count = count || 5; }
Mungkin terlihat seperti ini:
function ping(host, count) {
Verifikasi semacam itu lebih akrab, dan dalam beberapa kasus dapat membantu menghindari kesalahan.
Sebaliknya, tampaknya kebiadaban bagi pengembang yang awalnya memilih jalur JavaScript. Tetapi bagi sebagian besar orang lain, kode ini benar-benar liar:
var root = (typeof self == 'object' && self.self === self && self) || (typeof global == 'object' && global.global === global && global);
Ya, itu kompak, dan ya, perpustakaan populer dapat membelinya. Tapi tolong, jangan menyalahgunakannya, karena kode kita tidak akan dibaca oleh kontributor dalam JavaScript, tetapi oleh pengembang yang memecahkan masalah bisnis dalam kerangka waktu.
Pola seperti itu dapat terjadi sama sekali:
let count = typeof opts == 'object' && opts.count || 5;
Ini jelas lebih pendek dari operator ternary biasa, tetapi ketika membaca kode seperti itu, hal pertama yang Anda ingat adalah prioritas operasi yang digunakan.
Jika kita menulis fungsi predikat, yang kita lewati ke Array.prototype.filter yang sama, maka membungkus nilai kembali dalam Boolean adalah nada yang baik. Tujuan dari fungsi ini segera menjadi jelas dan tidak ada disonansi di antara pengembang yang bahasanya memiliki operator logis "benar".
Operasi bitwise
Contoh umum memeriksa keberadaan elemen dalam array atau substring dalam string menggunakan bitwise NOT (NOT), yang ditawarkan bahkan oleh beberapa tutorial:
if (~[1, 2, 3].indexOf(1)) { console.log('yes'); }
Masalah apa yang dipecahkan ini? kita tidak perlu memeriksa ! == -1 , karena indexOf akan mendapatkan indeks elemen atau -1, dan tilde akan menambahkan 1 dan mengubah tanda. Dengan demikian, ekspresi akan berubah menjadi "false" dalam kasus indeks -1.
Tetapi duplikasi kode dapat dihindari dengan cara lain: meletakkan tanda centang pada fungsi terpisah dari beberapa objek-utils, seperti yang dilakukan semua orang, daripada menggunakan operasi bitwise untuk tujuan lain. Ada fungsi menyertakan dalam lodash untuk ini, dan itu tidak berhasil brengsek tilde Anda dapat bersukacita, karena dalam ECMAScript 2016, metode Array.prototype.includes telah diperbaiki (baris juga memiliki satu).
Tapi itu dia! Tilde lain (bersama dengan XOR) digunakan untuk membulatkan angka, membuang bagian desimal:
console.log(~~3.14);
Tetapi ada parseInt atau Math.floor untuk keperluan ini. Operasi bitwise di sini nyaman untuk mengetik kode dengan cepat di konsol, karena mereka juga memiliki prioritas rendah selama sisa aritmatika. Tetapi pada ulasan kode, lebih baik jangan sampai ketinggalan.
Sintaks dan konstruksi bahasa
Beberapa praktik aneh sulit untuk dikaitkan dengan bagian tertentu. Misalnya, mereka mengatakan bahwa tanda kurung adalah opsional ketika memanggil konstruktor, dan dua ekspresi berikut ini identik:
let rabbit = new Rabbit(); let rabbit = new Rabbit;
Dan memang benar! tapi mengapa membuat pertanyaan dari awal? Tidak semua bahasa dapat membanggakan "fitur" tersebut. Dan jika Anda masih ingin, maka biarkan itu menjadi kesepakatan di seluruh proyek. Kalau tidak, ada perasaan salah bahwa ada beberapa perbedaan.
Situasi serupa dengan mendeklarasikan serangkaian variabel. Sintaks dari var dan biarkan arahan memungkinkan Anda untuk mendeklarasikan (dan mendefinisikan) beberapa variabel sekaligus, dipisahkan oleh koma:
let count = 5, host, retry = true;
Seseorang menggunakan umpan baris untuk keterbacaan, tetapi dalam hal apa pun, sintaks ini tidak umum dalam bahasa populer. Tidak ada yang akan membantu dan bertanya apakah Anda menulis seperti ini:
let count = 5; let retry = true; let host;
Sekali lagi, jika ada kesepakatan tentang gaya yang baik di tingkat proyek / perusahaan, maka tidak ada pertanyaan. Hanya saja Anda tidak perlu menggabungkan terlalu banyak sintaks untuk suasana hati Anda.
Ada konstruksi khusus dalam bahasa tersebut, seperti IIFE, yang memungkinkan Anda untuk memanggil fungsi segera di tempat definisinya. Triknya adalah agar parser mengenali ekspresi fungsional, bukan deklarasi fungsi. Dan ini dapat dilakukan dengan banyak cara berbeda: membungkus tanda kurung secara klasik, melalui kekosongan atau operator unary lainnya. Dan tidak ada yang luar biasa tentang itu! Penting untuk memilih satu-satunya pilihan dan tidak meninggalkannya tanpa perlu:
(function() { }());
Tidak perlu menggunakan operator untuk meretas parser. Ketika seorang pendatang baru datang ke proyek, saya ingin membenamkannya dalam logika bisnis aplikasi, dan tidak memberi makan dengan penjelasan dari mana semua tanda seru dan kekosongan ini dimata-matai. Ada juga entri tanda kurung klasik kedua dan komentar menarik dari Crockford tentang hal ini.
Munculnya sintaks kelas di ES6 tidak disertai dengan pengubah akses yang biasa. Dan terkadang pengembang ingin buang air kecil di kelas dan mengamati privasi. Yang mengarah ke kode Frankenstein ini:
class Person { constructor(name) { let _name = name; this.getName = function() { return _name; } } toString() { return `Hello, ${this.getName()}`; } }
Artinya, pengakses diciptakan untuk contoh dalam konstruktor, dan privasi dicapai dengan akses mereka ke variabel properti lokal melalui penutupan. Contoh ini terlihat bahkan Lacconcino, tetapi ini adalah pendekatan yang sepenuhnya tidak dapat dilakukan, kecuali jika Anda membangun solusi kerangka kerja yang terdokumentasi di sekitarnya. Tuan-tuan, mari kita gunakan kelas yang tersedia (dan tunggu standarisasi bidang pribadi), atau modul pola populer. Untuk membuat semacam solusi campuran menengah di sini adalah hal seperti itu untuk Anda sendiri, karena kelas tidak lagi menjadi kelas, dan kode dapat dipahami.
Kesimpulannya, ia akan membagikan akal sehatnya dengan panduan gaya yang diadopsi dalam proyek, konfigurasi untuk linter, atau hanya kode fragmen dengan rekan-rekan yang berkontribusi komponen non-JavaScript untuk proyek. Bahasa ini menawarkan beberapa opsi untuk setiap tugas yang khas, sehingga meningkatkan pemahaman satu sama lain dan jatuh di bawah common denominator tidak sulit (atau hampir).
Pelanggaran yang salah
Topik ini tentu saja holistik dan ada lebih banyak contoh, tetapi pesan utama dari artikel ini adalah Anda tidak boleh menyalahgunakan ketidakjelasan dalam JavaScript di mana hal ini dapat dihindari. Sifat bahasanya unik: memungkinkan Anda untuk menulis solusi yang elegan dan ekspresif (cukup "runcing"), serta dapat dimengerti dan dapat diakses oleh semua orang. Saya pada dasarnya tidak setuju dengan kebijaksanaan konvensional bahwa JavaScript "menghukum dirinya sendiri" atau "dimakamkan di bawah tumpukan niat baik dan kesalahan." Karena sekarang sebagian besar keanehan ditunjukkan bukan oleh bahasa, tetapi oleh budaya pengembang dan (tidak) acuh tak acuh yang terbentuk di sekitarnya.