Saya ingin menulis perpustakaan kelas JavaScript yang efisien tetapi saya tidak dapat memulai;
Cobalah untuk membaca perpustakaan orang lain, tetapi pahami seolah -olah dipahami;
Saya berencana untuk mempelajari fungsi -fungsi JS lanjutan dengan baik, tetapi konten dalam buku otoritatif terlalu tersebar.
Bahkan jika Anda ingat "penggunaan", Anda tidak memikirkan "metode" ketika Anda ingin "menggunakan".
Mungkin Anda, seperti saya, tampaknya memiliki kekuatan yang tidak terlihat yang menahan rencana kami, membuat kami berulang kali berpikir bahwa keterbatasan pengetahuan telah membuat kami diam dan sulit untuk bergerak maju.
Selama periode ini, berbagai pekerjaan rumah, desain kursus, dan laporan eksperimental meningkat dua kali lipat. Jarang untuk memeras sedikit waktu, tidak pernah tidur, dan memilah buku yang telah saya baca di masa lalu hanya untuk lebih dekat untuk menulis perpustakaan saya sendiri.
Artikel ini dirujuk dari "Esensi Bahasa JavaScript" dan "JavaScript yang Efektif". Semua contoh telah didebug. Setelah memahaminya, saya ingin membuat beberapa prinsip "mendalam" sedikit lebih sederhana.
1. Lingkup variabel
Lingkup seperti oksigen untuk pemrogram. Itu ada di mana -mana, dan Anda bahkan tidak memikirkannya. Tetapi ketika tercemar (seperti menggunakan objek global), Anda akan merasa tersedak (seperti respons aplikasi yang lambat). Aturan lingkup inti JavaScript sederhana, dirancang dengan cermat, dan sangat kuat. Penggunaan JavaScript yang efektif membutuhkan penguasaan beberapa konsep dasar ruang lingkup variabel dan memahami beberapa situasi ekstrem yang dapat menyebabkan masalah yang sulit dipahami dan menjengkelkan.
1.1 Cobalah untuk menggunakan variabel global sesedikit mungkin
JavaScript mudah membuat variabel dalam namespace global. Membuat variabel global mudah karena tidak memerlukan segala bentuk deklarasi dan dapat diakses secara otomatis oleh semua kode seluruh program.
Bagi kami pemula, ketika menemukan kebutuhan tertentu (misalnya, ketika data yang ditransmisikan dicatat, menunggu waktu tertentu dipanggil, atau ketika fungsi tertentu sering digunakan), kami akhirnya memikirkan fungsi global. Bahkan pemikiran yang berorientasi pada proses bahasa C yang saya pelajari di tahun pertama saya terlalu berakar dalam, dan sistem ini penuh dengan fungsi. Mendefinisikan variabel global dapat mencemari ruang nama publik bersama dan dapat menyebabkan konflik penamaan yang tidak terduga. Variabel global juga tidak kondusif untuk modularitas, karena menyebabkan penggabungan yang tidak perlu antara komponen independen dalam program. Serius berbicara, terlalu banyak global (termasuk lembar gaya, gaya div atau a) yang mendefinisikan langsung dan mengintegrasikannya ke dalam perkembangan banyak orang akan menjadi kesalahan besar. Inilah sebabnya mengapa semua kode jQuery dibungkus dengan ekspresi anonim yang dieksekusi secara instan - fungsi anonim mandiri. Ketika browser memuat file jQuery, ia memulai eksekusi segera setelah memanggil fungsi anonim, menginisialisasi berbagai modul jQuery untuk menghindari menghancurkan dan mencemari variabel global dan mempengaruhi kode lain.
Salinan kode adalah sebagai berikut:
(fungsi (jendela, tidak terdefinisi) {
var jQuery = ...
// ...
window.jQuery = window. $ = jQuery;
})(jendela);
Selain itu, Anda mungkin berpikir bahwa lebih mudah untuk "menulis bagaimana Anda terlebih dahulu dan mengaturnya nanti", tetapi programmer yang sangat baik akan terus memperhatikan struktur program, terus -menerus mengklasifikasikan fungsi terkait, dan komponen yang tidak relevan terpisah, dan perilaku ini adalah bagian dari formula pemrograman.
Karena ruang nama global adalah satu -satunya cara untuk komponen independen dalam program JavaScript untuk berinteraksi, penggunaan kontrol penamaan global tidak dapat dihindari. Komponen atau perpustakaan harus mendefinisikan beberapa variabel global. Untuk digunakan oleh bagian lain dari program ini. Kalau tidak, yang terbaik adalah menggunakan variabel lokal.
Salinan kode adalah sebagai berikut:
this.foo; // tidak terdefinisi
foo = "Global foo";
this.foo; // "Global foo"
var foo = "Global foo";
this.foo = "berubah";
foo; // diubah
Global namespace of JavaScript juga terpapar pada objek global yang dapat diakses dalam ruang lingkup global program, yang berfungsi sebagai nilai awal dari kata kunci ini. Di browser web, objek global terikat pada variabel jendela global. Ini berarti bahwa ada dua cara untuk membuat variabel global: mendeklarasikannya dengan var dalam ruang lingkup global, atau menambahkannya ke objek global. Keuntungan menggunakan deklarasi VAR adalah bahwa mereka dapat dengan jelas mengekspresikan dampak variabel global dalam ruang lingkup program.
Mengingat bahwa referensi ke variabel global yang terikat dapat menyebabkan kesalahan runtime, cakupan penghematan yang jelas dan ringkas akan memudahkan pengguna kode untuk memahami variabel -variabel global yang dinyatakan oleh program tersebut.
Karena objek global memberikan mekanisme respons dinamis untuk lingkungan global, itu dapat digunakan untuk menanyakan lingkungan yang sedang berjalan dan mendeteksi fitur mana yang tersedia di platform ini.
Eg.es5 memperkenalkan objek JSON global untuk membaca dan menulis data format JSON.
Salinan kode adalah sebagai berikut:
if (! this.json) {
this.json = {
Parse: ..,
Stringify: ...
}
}
Jika Anda memberikan implementasi JSON, tentu saja Anda dapat menggunakan implementasi Anda sendiri secara sederhana dan tanpa syarat. Tetapi implementasi bawaan yang disediakan oleh lingkungan host hampir lebih cocok karena ditulis ke dalam browser di C. karena mereka secara ketat memeriksa keakuratan dan konsistensi sesuai dengan standar tertentu dan umumnya memberikan kinerja yang lebih baik daripada implementasi pihak ketiga.
Operasi dasar string simulasi desain kursus struktur data mengharuskan metode yang disediakan oleh bahasa itu sendiri tidak dapat digunakan. JavaScript mengimplementasikan operasi dasar array dengan sangat baik. Jika hanya untuk kebutuhan belajar umum, gagasan metode simulasi yang disediakan oleh bahasa itu sendiri baik, tetapi jika Anda benar-benar berinvestasi dalam pengembangan, Anda tidak perlu mempertimbangkan untuk memilih untuk menggunakan metode bawaan JavaScript sesegera mungkin.
1.2 Hindari menggunakan dengan
Pernyataan dengan apa pun memberikan "kenyamanan" apa pun yang membuat aplikasi Anda tidak dapat diandalkan dan tidak efisien. Kita perlu memanggil serangkaian metode pada satu objek secara bergantian. Menggunakan pernyataan dengan dengan mudah menghindari referensi duplikat ke objek:
Salinan kode adalah sebagai berikut:
status fungsi (info) {
var widget = widget baru ();
dengan (widget) {
kemunduran ("biru");
setForeground ("putih");
setText ("Status:"+info);
menunjukkan();
}
}
Juga sangat menggoda untuk menggunakan variabel dengan pernyataan dengan "impor" (impor) dari objek modul.
Salinan kode adalah sebagai berikut:
fungsi f (x, y) {
dengan (matematika) {
return min (bundar (x), sqrt (y)); // kutipan abstrak
}
}
Bahkan, JavaScript memperlakukan semua variabel sama. Javascript dimulai dari ruang lingkup terdalam dan mencari variabel ke luar. Dengan bahasa memperlakukan objek seolah -olah mewakili ruang lingkup variabel, jadi di dalam blok kode dengan, pencarian variabel dimulai dengan mencari atribut dari nama variabel yang diberikan. Jika properti tidak ditemukan di objek ini, terus mencari di ruang lingkup eksternal. Referensi ke setiap variabel eksternal dalam blok dengan secara implisit mengasumsikan bahwa tidak ada atribut dengan nama yang sama dalam objek dengan (dan salah satu objek prototipe). Membuat atau memodifikasi objek dengan atau prototipe di tempat lain dalam program tidak harus mengikuti asumsi tersebut. Mesin JavaScript tentu tidak membaca kode lokal untuk mendapatkan variabel lokal yang Anda gunakan. Lingkup JavaScript dapat direpresentasikan sebagai struktur data internal yang efisien, dan pencarian variabel sangat cepat. Namun, karena blok dengan kode perlu mencari rantai prototipe objek untuk menemukan semua variabel dalam kode dengan, kecepatan berjalannya jauh lebih rendah daripada blok kode umum.
Alih -alih dengan bahasa, mudah untuk mengikat objek ke nama variabel pendek.
Salinan kode adalah sebagai berikut:
status fungsi (info) {
var w = widget baru ();
W.SetBackground ("Biru");
W.SetForeground ("White");
w.setText ("Status:"+info);
w.show ();
}
Dalam kasus lain, cara terbaik adalah secara eksplisit mengikat variabel lokal ke properti yang relevan.
Salinan kode adalah sebagai berikut:
fungsi f (x, y) {
var min = math.min,
Round = Math.round,
sqrt = math.sqrt;
return min (bundar (x), sqrt (y));
}
1.3 Mahir Penutupan
Ada satu konsep untuk memahami penutupan:
A) JavaScript memungkinkan Anda untuk merujuk variabel yang didefinisikan di luar fungsi saat ini.
Salinan kode adalah sebagai berikut:
function makeAndwich () {
var magicingredient = "selai kacang";
fungsi membuat (mengisi) {
Return MagicingRedient + "dan" + mengisi;
}
return make ("jelly");
}
MakeAndwich (); // "Peanut Butter and Jelly"
b) Bahkan jika fungsi eksternal telah dikembalikan, fungsi saat ini masih dapat merujuk ke variabel yang ditentukan oleh fungsi eksternal.
Salinan kode adalah sebagai berikut:
function makeAndwich () {
var magicingredient = "selai kacang";
fungsi membuat (mengisi) {
Return MagicingRedient + "dan" + mengisi;
}
return make;
}
var f = sandwichmaker ();
f ("jelly"); // "selai kacang dan jeli"
f ("pisang"); // "selai kacang dan pisang"
f ("Mallows"); // "selai kacang dan mallows"
Nilai fungsi JavaScriptd berisi lebih banyak informasi daripada kode yang diperlukan untuk dieksekusi saat dipanggil. Selain itu, nilai fungsi JavaScript juga menyimpan secara internal variabel yang mungkin mereka rujuk untuk didefinisikan dalam ruang lingkup terlampir. Fungsi -fungsi yang melacak variabel dalam ruang lingkup yang mereka tutupi disebut penutupan.
Fungsi Make adalah penutupan yang kodenya mengacu pada dua variabel eksternal: MagicingRedient dan mengisi. Setiap kali fungsi Make dipanggil, kodenya dapat merujuk pada dua variabel ini karena penutupan menyimpan kedua variabel ini.
Fungsi dapat merujuk ke variabel apa pun dalam ruang lingkupnya, termasuk variabel parameter dan fungsi eksternal. Kita dapat menggunakan ini untuk menulis fungsi sandwichmaker yang lebih umum.
Salinan kode adalah sebagai berikut:
function makeAndwich (MagicingRedient) {
fungsi membuat (mengisi) {
Return MagicingRedient + "dan" + mengisi;
}
return make;
}
var f = sandwichmaker ("ham");
f ("keju"); // "ham dan keju"
f ("mustard"); // "ham dan mustard"
Penutupan adalah salah satu fitur JavaScript yang paling elegan dan ekspresif dan juga merupakan inti dari banyak idiom.
c) Penutupan dapat memperbarui nilai variabel eksternal. Bahkan, penutupan menyimpan referensi ke variabel eksternal, bukan salinan nilainya. Oleh karena itu, setiap penutupan dengan akses ke variabel eksternal ini dapat diperbarui.
Salinan kode adalah sebagai berikut:
kotak fungsi () {
var val = tidak terdefinisi;
kembali {
set: function (newVal) {val = newVal;},
get: function () {return val;},
type: function () {return typeof val;}
};
}
var b = box ();
b.type (); //belum diartikan
b.set (98.6);
b.get (); // 98.6
b.type (); // nomor
Contoh ini menghasilkan objek yang berisi tiga penutupan. Ketiga penutupan ini diatur, mengetik dan mendapatkan properti, dan mereka semua berbagi akses ke variabel Val, dan penutupan penutupan memperbarui nilai Val. Kemudian hubungi dapatkan dan ketik untuk melihat hasil yang diperbarui.
1.4 Memahami peningkatan deklarasi variabel
JavaScript mendukung lingkup metode ini (referensi ke variabel FOO akan terikat pada ruang lingkup yang menyatakan yang paling dekat dengan variabel FOO), tetapi tidak mendukung ruang lingkup level blok (ruang lingkup yang ditentukan oleh variabel bukan pernyataan tertutup atau blok kode terdekat).
Tidak memahami fitur ini akan menyebabkan beberapa bug halus:
Salinan kode adalah sebagai berikut:
fungsi iswinner (pemain, lainnya) {
var tertinggi = 0;
untuk (var i = 0, n = orang lain. Panjang; i <n; i ++) {
var player = lainnya [i];
if (player.score> tertinggi) {
tertinggi = player.score;
}
}
return player.score> tertinggi;
}
1.5 Waspadalah terhadap ruang lingkup kikuk ekspresi fungsi penamaan
Salinan kode adalah sebagai berikut:
fungsi ganda (x) {return x*2; }
var f = function (x) {return x*2; }
Sepotong kode fungsi yang sama juga dapat digunakan sebagai ekspresi, tetapi memiliki makna yang sama sekali berbeda. Perbedaan resmi antara fungsi anonim dan ekspresi fungsi yang disebutkan adalah bahwa yang terakhir terikat pada variabel dengan nama fungsi yang sama dengan nama fungsinya, yang berfungsi sebagai variabel lokal dari fungsi tersebut. Ini dapat digunakan untuk menulis ekspresi fungsi rekursif.
Salinan kode adalah sebagai berikut:
var f = fungsi menemukan (pohon, kunci) {
// ...
return find (tree.left, key) ||
find (tree.right, kunci);
}
Perlu dicatat bahwa ruang lingkup temuan variabel hanya dalam fungsinya sendiri. Tidak seperti deklarasi fungsi, ekspresi fungsi yang disebut tidak dapat dirujuk secara eksternal melalui nama fungsi internalnya.
Salinan kode adalah sebagai berikut:
find (mytree, "foo"); // error: find tidak didefinisikan;
var constructor = function () {return null; }
var f = function () {
return constructor ();
};
f (); // {} (di lingkungan ES3)
Program ini sepertinya akan menghasilkan nol, tetapi sebenarnya akan menghasilkan objek baru.
Karena variabel fungsi bernama mewarisi objek.prototype.constructor (mis., Konstruktor Ojop), seperti halnya dengan pernyataan, ruang lingkup ini akan dipengaruhi oleh perubahan dinamis objek.prototype. Cara untuk menghindari objek yang mencemari ruang lingkup ekspresi fungsi dalam sistem adalah dengan menghindari menambahkan properti di objek.Prototipe kapan saja untuk menghindari menggunakan variabel lokal dengan nama yang sama dengan properti Object.Prototipe.
Kerugian lain dalam mesin JavaScript populer adalah promosi deklarasi ekspresi fungsi yang disebutkan.
Salinan kode adalah sebagai berikut:
var f = fungsi g () {return 17;}
G(); // 17 (di lingkungan non -prinsip)
Beberapa lingkungan JavaScript bahkan menggunakan dua fungsi F dan G sebagai objek yang berbeda, menghasilkan alokasi memori yang tidak perlu.
1.6 Waspadalah tentang Lingkup Kikuk untuk Fungsi Blok Lokal
Salinan kode adalah sebagai berikut:
fungsi f () {return "Global"; }
tes fungsi (x) {
fungsi f () {return "local";}
var result = [];
if (x) {
result.push (f ());
}
result.push (f ());
Hasil Hasil Hasil;
}
tes (benar); // ["lokal", "lokal"]
tes (false); //["lokal"]
Salinan kode adalah sebagai berikut:
fungsi f () {return "Global"; }
tes fungsi (x) {
var result = [];
if (x) {
fungsi f () {return "local";}
result.push (f ());
}
result.push (f ());
Hasil Hasil Hasil;
}
tes (benar); // ["lokal", "lokal"]
tes (false); //["lokal"]
JavaScript tidak memiliki ruang lingkup tingkat blok, sehingga ruang lingkup fungsi internal F harus menjadi seluruh fungsi uji. Beberapa lingkungan JavaScript melakukannya, tetapi tidak semua lingkungan JavaScript melakukannya. Implementasi JavaScript melaporkan fungsi-fungsi seperti kesalahan dalam mode ketat (program dalam mode ketat dengan deklarasi fungsi blok lokal akan melaporkan sebagai kesalahan sintaks), yang membantu mendeteksi kode non-portabel, memberikan lebih banyak semantik dan kemungkinan semantik untuk deklarasi fungsi blok lokal untuk versi standar di masa depan. Dalam hal ini, dimungkinkan untuk mempertimbangkan mendeklarasikan variabel lokal dalam fungsi pengujian untuk menunjuk ke fungsi global f.