Perkenalan
Dalam banyak bahasa tradisional (C/C ++/Java/C#, dll.), Fungsi ada sebagai warga negara kelas dua. Anda hanya dapat mendeklarasikan fungsi dengan kata kunci bahasa dan kemudian menyebutnya. Jika Anda perlu meneruskan fungsi sebagai parameter ke fungsi lain, atau menetapkan nilai ke variabel lokal, atau sebagai nilai pengembalian, Anda perlu membuat terobosan melalui metode khusus seperti pointer fungsi dan proxy (delegasi).
Di dunia JavaScript, fungsi adalah warga negara kelas satu. Mereka tidak hanya memiliki semua cara menggunakan fungsi tradisional (deklarasi dan panggilan), tetapi juga dapat menetapkan nilai, lulus parameter, dan mengembalikan seperti nilai -nilai sederhana. Fungsi seperti itu juga disebut fungsi kelas satu. Tidak hanya itu, fungsi dalam JavaScript juga bertindak sebagai konstruktor kelas, dan juga merupakan contoh kelas fungsi. Berbagai identitas seperti itu membuat fungsi JavaScript sangat penting.
1. Fungsi JavaScript Level Entri
Seperti bahasa biasa, fungsi JavaScript juga mengikuti prinsip deklarasi terlebih dahulu dan kemudian digunakan. Nama fungsi hanya dapat berisi huruf, angka, garis bawah atau $, dan tidak dapat memulai dengan angka. Ada dua cara umum untuk mendeklarasikan fungsi:
Salinan kode adalah sebagai berikut:
// menyatakan fungsi myfunc secara langsung
fungsi myfunc (/ * argumen */) {
}
// Tetapkan fungsi anonim ke variabel lokal myfunc
var myfunc = function (/ * argumen */) {
}
Perhatikan bahwa ada perbedaan halus dalam dua metode deklarasi di atas: metode pertama adalah fungsi bernama ketika dinyatakan, apakah itu fungsi yang dinyatakan sebelumnya, setelah panggilan, atau bahkan lokasi di mana ia tidak akan dieksekusi (misalnya, setelah pernyataan pengembalian atau di cabang yang tidak akan pernah benar), dapat diakses di seluruh ruang lingkup; Metode kedua adalah menetapkan fungsi anonim ke variabel. Sebenarnya, ini bukan deklarasi fungsi tetapi ekspresi fungsi. Sebelum penugasan, fungsi ini tidak dapat diakses oleh kode apa pun, yang berarti bahwa penugasan harus diselesaikan sebelum panggilan, jika tidak, kesalahan akan muncul ketika memanggil: "TypeError: Undefined bukan fungsi". Misalnya:
Salinan kode adalah sebagai berikut:
myfunc1 (); // dapat dipanggil secara normal, karena myfunc1 menggunakan metode deklarasi langsung
fungsi myfunc1 () {
}
myfunc2 (); // kesalahan typeerror: tidak terdefinisi bukan fungsi
var myfunc2 = function () {
};
Metode fungsi panggilan dasar disebut dengan cara yang sama seperti dalam bahasa tradisional: myfunc (). Fungsi JavaScript juga mendukung panggilan rekursif langsung atau tidak langsung. Misalnya, fungsi Fibonacci klasik dapat diimplementasikan dalam JavaScript seperti ini:
Salinan kode adalah sebagai berikut:
fungsi fib (n) {
if (n == 1 || n == 2) {
kembali 1;
} kalau tidak {
return fib (n - 2) + fib (n - 1);
}
}
Fungsi dalam JavaScript dapat menangani parameter panjang variabel. Mereka semua memiliki variabel lokal yang disebut argumen di dalam fungsi. Ini adalah objek seperti array yang berisi semua parameter yang dilewati saat menelepon, dan memiliki atribut panjang untuk mewakili jumlah parameter. Misalnya:
Salinan kode adalah sebagai berikut:
function test () {
peringatan (argumen.length);
}
tes (1); // 1
tes (1, 'a'); // 2
test (true, [], {}); // 3 Gunakan argumen untuk mengimplementasikan fungsi yang mirip dengan printf dalam bahasa C, dan juga dapat digunakan untuk mengimplementasikan polimorfisme metode.
2. Fungsi JavaScript Lanjutan
2.1 fungsi anonim dan bersarang
Dalam JavaScript, Anda dapat mendeklarasikan fungsi tanpa nama, yang disebut fungsi anonim (fungsi anonim). Pada saat yang sama, JavaScript juga memungkinkan deklarasi fungsi di dalam fungsi, yang disebut fungsi bersarang, dan ruang lingkup fungsi bersarang adalah seluruh fungsi induk.
Pada bagian sebelumnya dari deklarasi fungsi, saya melihat penggunaan fungsi anonim dan fungsi bersarang. Karena fungsi anonim tidak memiliki nama, mereka tidak akan memperkenalkan variabel baru untuk mencemari konteks dan akan membawa lingkup variabel baru. Oleh karena itu, fungsi anonim sering digunakan untuk mencegah polusi lingkungan global.
Ada objek global khusus dalam runtime JavaScript. Objek ini menyimpan fungsi dan variabel global. Dalam pengembangan aktual, beberapa perpustakaan pihak ketiga atau beberapa file JS sering digunakan. Jika Anda secara tidak sengaja memperkenalkan variabel duplikat atau deklarasi fungsi ke dalam objek global, itu akan menyebabkan kebingungan dalam eksekusi kode. Misalnya, dua file JS diperkenalkan secara berturut -turut, dan log fungsi mereka sendiri didefinisikan sebagai penggunaan internal. Fungsi yang diperkenalkan kedua akan menimpa definisi yang pertama dan tidak akan melakukan kesalahan. Memanggil fungsi log dalam eksekusi selanjutnya dapat menyebabkan kesalahan. Pada saat ini, menggunakan fungsi anonim untuk membungkus logika di seluruh JS dapat menghindari kesalahan ini. Metode ini telah digunakan oleh sebagian besar pustaka JS sumber terbuka.
Salinan kode adalah sebagai berikut:
(function () {// fungsi anonim
function log (msg) {
console.log (msg);
}
// kode lain
} ()); // Jalankan segera
Kode di atas adalah contoh sederhana. Lingkup fungsi log terbatas pada fungsi anonim ini. Fungsi anonim termasuk dalam sepasang tanda kurung () di luar untuk membentuk ekspresi fungsi. Nilai ekspresi adalah fungsi, diikuti oleh sepasang tanda kurung untuk menunjukkan bahwa fungsi tersebut dieksekusi segera, sehingga kode asli dapat dieksekusi secara normal. Namun, fungsi yang dinyatakan dengan cara ini, variabel yang dinyatakan melalui VAR, dll. Adalah internal dan tidak dapat diakses oleh kode apa pun selain fungsi anonim. Jika Anda perlu mengekspos beberapa fungsi sebagai antarmuka, ada beberapa metode:
Salinan kode adalah sebagai berikut:
var mylib = (function (global) {
function log (msg) {
console.log (msg);
}
log1 = log; // Metode 1: Gunakan perilaku default deklarasi variabel tanpa var untuk menjadi variabel global di log1 (tidak disarankan)
global.log2 = log; // Metode 2: Langsung tambahkan atribut log2 ke objek global dan tetapkan ke fungsi log (disarankan)
Return {// Metode 3: Mengembalikan serangkaian objek koleksi fungsi antarmuka melalui fungsi anonim dan menetapkannya ke variabel global mylib (disarankan)
Log: log
};
}(jendela));
2.2 Fungsi orde tinggi
Jika fungsi digunakan sebagai parameter atau nilai pengembalian, itu disebut fungsi orde tinggi. Fungsi dalam JavaScript dapat digunakan sebagai fungsi tingkat tinggi, yang juga merupakan fitur dari jenis fungsi pertama. Mari kita analisis dua metode penggunaan di bawah ini.
Salinan kode adalah sebagai berikut:
fungsi negatif (n) {
kembali -n; // ambil nilai sebaliknya n
}
function square (n) {
kembali n*n; // persegi n
}
Proses fungsi (nums, callback) {
var result = [];
untuk (var i = 0, panjang = nums.length; i <panjang; i ++) {
hasil [i] = callback (num [i]); // Lewati semua elemen di array num untuk panggilan balik untuk diproses, dan menyimpan nilai pengembalian sebagai hasilnya
}
hasil pengembalian;
}
var nums = [-3, -2, -1, 0, 1, 2, 3, 4];
var n_neg = proses (nums, negatif);
// n_neg = [3, 2, 1, 0, -1, -2, -3, -4];
var n_square = proses (nums, square);
// n_square = [9, 4, 1, 0, 1, 4, 9, 16];
Kode di atas menunjukkan contoh melewati fungsi sebagai parameter ke panggilan proses fungsi lain. Dalam implementasi fungsi proses, panggilan balik dianggap sebagai kotak hitam, bertanggung jawab untuk meneruskan parameter ke sana, dan kemudian mendapatkan nilai pengembalian. Implementasi spesifik panggilan balik tidak jelas sebelum panggilan. Hanya ketika 20 dan 22 baris dieksekusi, panggilan balik masing -masing diwakili oleh negatif atau kuadrat, dan setiap elemen diambil dengan nilai yang berlawanan atau nilai kuadrat.
Salinan kode adalah sebagai berikut:
function generator () {
var i = 0;
return function () {
return i ++;
};
}
var gen1 = generator (); // Dapatkan generator bilangan alami
var gen2 = generator (); // Dapatkan generator bilangan alami lainnya
var r1 = gen1 (); // r1 = 0
var r2 = gen1 (); // r2 = 1
var r3 = gen2 (); // r3 = 0
var r4 = gen2 (); // r4 = 1
Kode di atas menunjukkan contoh menggunakan fungsi sebagai nilai pengembalian. Generator adalah fungsi generator bilangan alami, dan nilai pengembalian adalah fungsi generator bilangan alami. Setiap kali generator dipanggil, fungsi anonim akan dikembalikan sebagai hasilnya. Fungsi anonim ini mengembalikan setiap angka alami secara bergantian ketika sebenarnya disebut. Variabel I dalam generator akan meningkat sebesar 1 setiap kali fungsi anonim ini disebut, yang sebenarnya merupakan penutupan. Mari kita perkenalkan penutupan di bawah ini.
2.3 Penutupan
Penutupan bukanlah konsep baru, dan banyak bahasa fungsional menggunakan penutupan. Dalam JavaScript, ketika Anda menggunakan variabel dalam ruang lingkup fungsi eksternal dalam fungsi tertanam, Anda menggunakan penutupan. Gunakan analogi yang umum digunakan untuk menjelaskan hubungan antara penutupan dan kelas: kelas adalah data dengan fungsi, dan penutupan adalah fungsi dengan data.
Variabel yang digunakan dalam penutupan memiliki karakteristik bahwa mereka tidak dilepaskan ketika fungsi induk kembali, tetapi diakhiri dengan akhir siklus hidup penutupan. Misalnya, seperti dalam contoh generator di bagian sebelumnya, Gen1 dan Gen2 menggunakan variabel independen I masing -masing (ketika Gen1 I meningkat sebesar 1, Gen2 I tidak akan terpengaruh, dan sebaliknya). Selama dua variabel Gen1 atau Gen2 bukan sampah yang dikumpulkan oleh mesin JavaScript, variabel masing -masing saya tidak akan dilepaskan. Dalam pemrograman JavaScript, penutupan digunakan secara tidak sadar. Fitur penutupan ini mudah digunakan, tetapi juga dengan mudah menyebabkan masalah kebocoran memori. Misalnya:
Salinan kode adalah sebagai berikut:
var elem = document.geteLementById ('test');
elem.addeventListener ('klik', function () {
peringatan ('Anda mengklik' + elem.tagname);
});
Tujuan kode ini adalah untuk menampilkan nama labelnya saat mengklik node. Ini mendaftarkan fungsi anonim sebagai fungsi penanganan acara klik dari sebuah node DOM. ELEM objek DOM dirujuk dalam fungsi, yang membentuk penutupan. Ini akan menghasilkan referensi melingkar, yaitu: dom-> clossary-> dom-> closarium ... objek DOM tidak akan dirilis sebelum penutupan dilepaskan; Dan penutupan ada sebagai fungsi penanganan acara dari objek DOM, sehingga penutupan tidak akan dirilis sebelum objek DOM dirilis. Bahkan jika objek DOM dihapus di pohon DOM, karena adanya referensi melingkar ini, baik objek DOM maupun penutupan tidak akan dilepaskan. Kebocoran memori ini dapat dihindari menggunakan metode berikut:
Salinan kode adalah sebagai berikut:
var elem = document.geteLementById ('test');
elem.addeventListener ('klik', function () {
peringatan ('Anda mengklik' + this.tagname); // Tidak ada lagi referensi langsung variabel elem
});
Dalam kode di atas, ini digunakan sebagai pengganti Elem (pointer ini menunjuk ke elemen DOM itu sendiri dalam fungsi penanganan acara DOM), sehingga runtime JS tidak lagi percaya bahwa fungsi tersebut menggunakan variabel kelas induk, sehingga tidak lagi membentuk penutupan.
Penutupan juga akan membawa banyak masalah kebocoran memori yang serupa. Anda hanya dapat memperhatikan penutupan saat menulis kode dan mencoba menghindari masalah seperti itu.
2.4 Konstruktor Kelas
Fungsi JavaScript juga digunakan sebagai konstruktor kelas, sehingga Anda dapat menggunakan kata kunci baru untuk membuat instance kelas selama Anda mendeklarasikan fungsi.
Salinan kode adalah sebagai berikut:
function person (name) {
this.name = name;
this.toString = function () {
kembalikan 'halo,' + this.name + '!';
};
}
var p = orang baru ('GhostTheAven');
peringatan (p); // halo, Ghosttheaven! Dalam contoh di atas, fungsi orang digunakan sebagai konstruktor kelas. Pada saat ini, ini menunjuk pada objek instance yang baru dibuat, dan dapat menambahkan properti dan metode ke instance. Untuk pemrograman JavaScript yang berorientasi objek terperinci, silakan merujuk ke artikel ini. Yang ingin saya katakan di sini adalah masalah nilai pengembalian saat menggunakan fungsi JavaScript sebagai konstruktor kelas.
Salinan kode adalah sebagai berikut:
function myclass (name) {
this.name = name;
nama pengembalian; // Nilai pengembalian konstruktor?
}
var obj1 = myclass baru ('foo');
var obj2 = myclass ('foo');
var obj3 = myclass baru ({});
var obj4 = myclass ({});
Konstruktor di atas cukup istimewa, dengan pernyataan pengembalian, jadi objek apa yang ditunjukkan oleh obj1 ~ obj4? Hasil sebenarnya adalah ini:
Salinan kode adalah sebagai berikut:
obj1 = objek myclass
obj2 = 'foo'
obj3 = {}
obj4 = {}
Alasan spesifik dijelaskan dalam artikel ini, dan saya tidak akan mengulanginya dalam artikel ini. Karena konstruktor dengan nilai pengembalian akan menghasilkan hasil yang aneh, jangan panggil pernyataan pengembalian dengan nilai pengembalian di konstruktor (pengembalian kosong dapat dilakukan).
3. JavaScript Fungsi Level Monster
Selamat datang di area pengajaran fungsi tingkat monster, di mana Anda akan diberi cara menghadapi monster lama dengan tenang dan bebas. . .
3.1 Kelas Fungsi
Ada kelas bawaan yang disebut fungsi dalam runtime JavaScript. Mendeklarasikan fungsi dengan kata kunci fungsi sebenarnya adalah singkatan untuk membuat objek kelas fungsi. Semua fungsi memiliki semua metode kelas fungsi, seperti panggilan, berlaku, mengikat, dll. Anda dapat memverifikasi pernyataan ini melalui kata kunci kata kunci.
Karena fungsi adalah kelas, konstruktornya adalah fungsi (itu sendiri merupakan objek dari kelas fungsi), dan objek fungsi harus dihasilkan melalui kata kunci baru. Monster pertama ada di sini, yaitu cara membangun fungsi menggunakan kelas fungsi. Sintaks fungsi adalah sebagai berikut:
Salinan kode adalah sebagai berikut:
fungsi baru ([arg1 [, arg2 [, ... argn]],] functionbody)
di mana arg1, arg2, ... argn adalah string, mewakili nama parameter, dan functionbody juga merupakan string, mewakili tubuh fungsi. Nama parameter sebelumnya lebih atau kurang. Konstruktor fungsi akan memperlakukan parameter terakhir sebagai badan fungsi, dan yang sebelumnya sebagai parameter.
Salinan kode adalah sebagai berikut:
var func1 = fungsi baru ('name', 'return "hello," + name + "!";');
func1 ('ghosttheaven'); // halo, Ghosttheaven!
Metode di atas membangun fungsi melalui fungsi, yang persis sama dengan fungsi lain yang dinyatakan dengan kata kunci fungsi.
Melihat ini, banyak orang mungkin bertanya mengapa monster seperti itu dibutuhkan? "Apa yang ada masuk akal", kelas fungsi memiliki tujuan yang unik. Anda dapat menggunakannya untuk secara dinamis menghasilkan berbagai logika fungsi, atau mengganti fungsi fungsi eval, dan menjaga lingkungan saat ini agar tidak tercemar*.
3.2 Fungsi Pembaruan Diri
Dalam banyak bahasa, setelah suatu fungsi telah dinyatakan, ia tidak dapat menyatakan fungsi dari nama yang sama lagi, jika tidak kesalahan sintaks akan terjadi. Fungsi dalam JavaScript tidak hanya dapat dinyatakan berulang kali, tetapi juga memperbarui diri mereka sendiri. Monster yang saya makan ada di sini!
Salinan kode adalah sebagai berikut:
function selfupdate () {
window.selfupdate = function () {
waspada ('run kedua!');
};
waspada ('run pertama!');
}
selfupdate (); // lari pertama!
selfupdate (); // lari kedua! Fungsi ini dapat digunakan untuk logika yang dijalankan hanya sekali, dan setelah menjalankan pertama, diganti dengan logika baru.
ringkasan
Fungsi JavaScript sangat kuat. Sambil memecahkan banyak masalah dengan indah, mereka juga membawa banyak masalah negatif. Fungsi tingkat monster biasanya digunakan dengan penggunaan yang sedikit diketahui. Kecuali sangat diperlukan, itu akan menyebabkan kesulitan membaca kode dan mempengaruhi efisiensi pengembangan tim.
* Mode ketat diperkenalkan dalam ecmascript baru. Dalam mode yang ketat, fungsi eval sangat dibatasi dan dapat memastikan bahwa lingkungan tidak tercemar.
Apakah Anda mengerti, ini sangat praktis. Jika ada tempat yang hilang, beri saya saran dan buat kemajuan bersama.