Kata "pit" berarti "jebakan". Karena sifat "bahasa lemah" Javascript, sangat longgar dan fleksibel selama digunakan, tetapi juga sangat mudah untuk "dipukul". Lubang -lubang ini sering disembunyikan, jadi Anda harus tetap membuka mata untuk lancar berlayar di jalan belajar dan menerapkan JS.
1. Variabel global
JavaScript mengelola lingkup melalui fungsi. Variabel yang dinyatakan di dalam suatu fungsi hanya di dalam fungsi ini dan tidak tersedia di luar fungsi. Di sisi lain, variabel global dinyatakan di luar fungsi apa pun atau digunakan secara sederhana dan hanya tanpa deklarasi.
"Gunakan hanya tanpa menyatakan" berarti bahwa variabel dinyatakan tanpa menggunakan kata kunci VAR. Kami telah memperjelas bahwa cara untuk menghindari secara implisit menghasilkan variabel global adalah dengan mendeklarasikan variabel dengan kata kunci VAR sebanyak mungkin.
Tapi apakah menurut Anda tidak apa -apa menggunakan var? Mari kita lihat lubang ini:
Salinan kode adalah sebagai berikut:
fungsi foo () {
var a = b = 0;
// tubuh...
}
Mungkin yang Anda harapkan adalah dua variabel lokal, tetapi B adalah variabel global nyata. Mengapa? Karena operasi penugasan berasal dari kanan ke kiri, jadi ini setara dengan:
Salinan kode adalah sebagai berikut:
fungsi foo () {
var a = (b = 0);
// tubuh...
}
Jadi B adalah variabel global.
Isi Pit: Deklarasi Variabel, yang terbaik adalah datang satu per satu, jangan lakukan grosir ~ _ ~;
2. Deklarasi Variabel
Mari kita lihat pit terlebih dahulu:
Salinan kode adalah sebagai berikut:
myName = "global";
fungsi foo () {
waspada (myName);
var myname = "lokal";
waspada (myName);
}
foo ();
Pada pandangan pertama, kami berharap untuk mengharapkan hasil dari dua peringatan menjadi "global" dan "lokal", tetapi hasil sebenarnya "tidak ditentukan" dan "lokal". Mengapa? Karena variabel dinyatakan dalam ruang lingkup yang sama (fungsi yang sama), dan pertama kali diuraikan oleh bagian atas ruang lingkup.
Jadi perilaku eksekusi cuplikan kode di atas mungkin terlihat seperti ini:
Salinan kode adalah sebagai berikut:
fungsi foo () {
var myname;
waspada (myName); // "belum diartikan"
myName = "lokal";
waspada (myName); // "lokal"
}
Gunakan lubang lain untuk menguji apakah Anda benar-benar memahami pra-peluang:
Salinan kode adalah sebagai berikut:
if (! ("a" di jendela)) {
var a = 1;
}
waspada (a);
Deklarasi suatu variabel dikemukakan ke bagian atas kode dan belum ditetapkan. Selanjutnya, masukkan pernyataan IF, dan menilai bahwa "A" di jendela ditetapkan (A telah dinyatakan sebagai variabel global), sehingga hasil perhitungan pernyataan penilaian salah, dan pernyataan IF akan melompat keluar, sehingga nilai A tidak terdefinisi.
Salinan kode adalah sebagai berikut:
var a; // "belum diartikan"
console.log ("a" di jendela); // BENAR
if (! ("a" di jendela)) {
var a = 1; // tidak dieksekusi
}
waspada (a); // "belum diartikan"
Isi lubang: yang terbaik adalah menempatkan deklarasi variabel secara manual di bagian atas ruang lingkup. Untuk variabel yang tidak dapat ditetapkan saat ini, Anda dapat menggunakan metode untuk mendeklarasikan terlebih dahulu dan kemudian menetapkan nilai.
3. Deklarasi Fungsi
Deklarasi fungsi juga maju ke atas ruang lingkup, dan diuraikan dan dievaluasi sebelum ekspresi dan pernyataan diuraikan dan dievaluasi.
Salinan kode adalah sebagai berikut:
waspada (typeof foo); // "fungsi"
fungsi foo () {
// tubuh...
}
Anda dapat membandingkannya:
Salinan kode adalah sebagai berikut:
waspada (typeof foo); // "belum diartikan"
var foo = function () {
// tubuh...
};
Jika Anda memahami prinsip ini, apakah Anda akan tetap jatuh ke dalam jebakan berikut?
Salinan kode adalah sebagai berikut:
function test () {
peringatan ("1");
}
tes();
function test () {
peringatan ("2");
}
tes();
Saat menjalankan cuplikan kode di atas, jendela pop-up yang Anda lihat adalah "2", mengapa mereka tidak "1" dan "2" masing-masing? Sangat sederhana, deklarasi tes diuraikan sebelum tes (). Karena yang terakhir mengesampingkan yang pertama, hasil dari kedua eksekusi adalah "2".
Isi lubang: Dalam kebanyakan kasus, saya menggunakan ekspresi fungsi alih -alih deklarasi fungsi, terutama dalam beberapa blok pernyataan.
4. Ekspresi fungsi
Mari kita lihat ekspresi fungsi bernama terlebih dahulu. Tentu saja, itu harus memiliki nama, misalnya:
Salin kode sebagai berikut: var bar = fungsi foo () {
// tubuh...
};
Perlu dicatat bahwa nama fungsi hanya terlihat oleh fungsinya di dalam. Seperti jebakan berikut:
Salinan kode adalah sebagai berikut:
var bar = function foo () {
foo (); // jalankan secara normal
};
foo (); // Kesalahan: ReferenceError
Isi lubang: Cobalah menggunakan ekspresi fungsi bernama sesedikit mungkin (kecuali untuk beberapa tujuan rekursi dan debugging), dan jangan pernah menggunakan nama fungsi secara eksternal.
5. Fungsi Ekseksi Diri
Untuk ekspresi fungsi, Anda dapat mengeksekusi dengan menambahkan () sesudahnya, dan parameter dapat diteruskan dalam tanda kurung, sedangkan deklarasi fungsi tidak bisa. lubang:
Salinan kode adalah sebagai berikut:
// (1) Ini hanya operator pengelompokan, bukan panggilan fungsi!
// Jadi fungsinya di sini belum dieksekusi, itu masih merupakan pernyataan
fungsi foo (x) {
peringatan (x);
} (1);
Cuplikan kode berikut dieksekusi secara terpisah, dan jendela pop-up menunjukkan "1". Karena sebelum (1), mereka adalah ekspresi fungsi, jadi () di sini bukan operator pengelompokan, tetapi operator, yang menunjukkan eksekusi panggilan.
Salin kode sebagai berikut: // Ekspresi Fungsi Anonim Standar
var bar = function foo (x) {
peringatan (x);
} (1);
// sebelumnya () mengubah deklarasi fungsi menjadi ekspresi
(function foo (x) {
peringatan (x);
}) (1);
// keseluruhan () adalah ekspresi
(function foo (x) {
peringatan (x);
} (1));
// Ekspresi baru
fungsi baru foo (x) {
peringatan (x);
} (1);
// &&, || ,!, +, -, ~ dll. Operator (dan koma) untuk ekspresi fungsi dan deklarasi fungsi disambiguate
// Jadi begitu parser tahu bahwa salah satunya adalah ekspresi, yang lain juga akan default untuk ekspresi.
true && function foo (x) {
peringatan (x);
} (1);
Isi lubang: Kunci dari lubang ini adalah untuk mencari tahu esensi dari semua jenis ekspresi fungsi.
6. Penutupan di Loop
Berikut ini menunjukkan jebakan umum:
Salinan kode adalah sebagai berikut:
<! Doctype html>
<html lang = "en">
<head>
<meta charset = "UTF-8">
<title> dokumen </iteme>
</head>
<body>
<h3> Saat mengklik tautan di bawah ini, tunjukkan jumlah urutannya </h3>
<ul>
<li> <a href = " #"> tautan #0 </a> </li>
<li> <a href = " #"> tautan #1 </a> </li>
<li> <a href = " #"> tautan #2 </a> </li>
<li> <a href = " #"> tautan #3 </a> </li>
<li> <a href = " #"> tautan #4 </a> </li>
</ul>
</body>
</html>
Salinan kode adalah sebagai berikut:
var links = document.geteLementsByTagname ("ul") [0] .geteLementsByTagname ("a");
untuk (var i = 0, l = links.length; i <l; i ++) {
tautan [i] .onClick = function (e) {
e.preventdefault ();
peringatan ("Anda mengklik tautan #" + i);
}
}
Kami berharap bahwa ketika mengklik tautan i-th, kami mendapatkan nilai indeks I dalam urutan ini. Namun, tidak peduli tautan mana yang diklik, kami mendapatkan hasil akhir dari saya setelah loop: "5".
Jelaskan alasannya: Ketika peringatan dipanggil, ekspresi fungsi anonim dalam loop untuk mempertahankan referensi ke variabel eksternal I (penutupan). Pada saat ini, loop telah berakhir dan nilai I dimodifikasi menjadi "5".
Isi lubang: Untuk mendapatkan hasil yang diinginkan, Anda perlu membuat salinan variabel I di setiap loop. Berikut ini menunjukkan pendekatan yang benar:
Salinan kode adalah sebagai berikut:
<head>
<meta charset = "UTF-8">
<title> dokumen </iteme>
</head>
<body>
<h3> Saat mengklik tautan di bawah ini, tunjukkan jumlah urutannya </h3>
<ul>
<li> <a href = " #"> tautan #0 </a> </li>
<li> <a href = " #"> tautan #1 </a> </li>
<li> <a href = " #"> tautan #2 </a> </li>
<li> <a href = " #"> tautan #3 </a> </li>
<li> <a href = " #"> tautan #4 </a> </li>
</ul>
</body>
</html>
Salinan kode adalah sebagai berikut:
var links = document.geteLementsByTagname ("ul") [0] .geteLementsByTagname ("a");
untuk (var i = 0, l = links.length; i <l; i ++) {
tautan [i] .onClick = (function (index) {
fungsi pengembalian (e) {
e.preventdefault ();
peringatan ("Anda mengklik tautan #" + indeks);
}
})(Saya);
}
Seperti yang Anda lihat, bentuk (function () {...}) () adalah pengajuan diri dari fungsi yang disebutkan di atas. Saya diteruskan ke indeks sebagai parameter. Ketika peringatan mengeksekusi lagi, ia memiliki referensi ke indeks. Pada saat ini, nilai ini tidak akan diubah oleh loop. Tentu saja, setelah memahami prinsipnya, Anda juga dapat menulis seperti ini:
Salinan kode adalah sebagai berikut:
untuk (var i = 0, l = links.length; i <l; i ++) {
(function (index) {
tautan [i] .onClick = function (e) {
e.preventdefault ();
peringatan ("Anda mengklik tautan #" + indeks);
}
})(Saya);
}
Itu bekerja juga.