Saya baru-baru ini mulai memelihara kode JavaScript orang lain. Saya memperbaiki bug, menambahkan fitur dan juga mencoba merapikan kode dan membuatnya lebih konsisten.
Pengembang sebelumnya menggunakan dua cara untuk mendeklarasikan fungsi dan saya tidak dapat menentukan apakah ada alasan di baliknya atau tidak.
Dua cara tersebut adalah:
var functionOne = function() {
// Some code
};
function functionTwo() {
// Some code
}
Apa alasan untuk menggunakan dua metode yang berbeda ini dan apa pro dan kontra masing-masing? Adakah yang bisa dilakukan dengan satu metode yang tidak bisa dilakukan dengan yang lain?
javascript
function
syntax
idioms
Richard Garside
sumber
sumber
var a = 1; var b = 2;
menjadivar a; var b; a = 1; b = 2
. Jadi ketika Anda mendeklarasikan functionOne, itu akan dideklarasikan tetapi nilainya tidak segera ditetapkan. Sedangkan karena functionTwo hanya deklarasi, itu akan diletakkan di bagian atas ruang lingkup. Function # 2Two memungkinkan Anda mengakses properti nama dan itu banyak membantu ketika mencoba men-debug sesuatu.function f(){}
vsvar f = function(){};
.Jawaban:
Perbedaannya adalah bahwa itu
functionOne
adalah ekspresi fungsi dan hanya ditentukan ketika garis itu tercapai, sedangkanfunctionTwo
adalah deklarasi fungsi dan didefinisikan segera setelah fungsi atau skrip sekitarnya dijalankan (karena mengangkat ).Misalnya, ekspresi fungsi:
Dan, deklarasi fungsi:
Secara historis, deklarasi fungsi yang didefinisikan dalam blok-blok ditangani secara tidak konsisten antar browser. Mode ketat (diperkenalkan dalam ES5) menyelesaikan ini dengan meringkas deklarasi fungsi ke blok penutupnya.
sumber
functionOne
hanyalah sebuah variabel yang memiliki fungsi anonim yang ditugaskan untuknya, sedangkanfunctionTwo
sebenarnya adalah fungsi bernama. Panggil.toString()
keduanya untuk melihat perbedaannya. Ini penting dalam beberapa kasus di mana Anda ingin mendapatkan nama fungsi secara terprogram.function expression
yang kedua adalahfunction declaration
. Anda dapat membaca lebih lanjut tentang topik ini di sini: javascriptweblog.wordpress.com/2010/07/06/…Pertama, saya ingin mengoreksi Greg:
function abc(){}
dicakup juga - namanyaabc
didefinisikan dalam lingkup di mana definisi ini ditemukan. Contoh:Kedua, dimungkinkan untuk menggabungkan kedua gaya:
xyz
akan didefinisikan seperti biasa,abc
tidak terdefinisi di semua browser tetapi Internet Explorer - jangan bergantung pada itu yang didefinisikan. Tetapi itu akan didefinisikan di dalam tubuhnya:Jika Anda ingin alias fungsi di semua browser, gunakan deklarasi semacam ini:
Dalam hal ini, baik
xyz
danabc
adalah alias dari objek yang sama:Salah satu alasan kuat untuk menggunakan gaya gabungan adalah atribut "nama" objek fungsi ( tidak didukung oleh Internet Explorer ). Pada dasarnya ketika Anda mendefinisikan fungsi seperti
namanya ditetapkan secara otomatis. Tetapi ketika Anda mendefinisikannya seperti
namanya kosong - kami membuat fungsi anonim dan menugaskannya ke beberapa variabel.
Alasan lain yang baik untuk menggunakan gaya gabungan adalah untuk menggunakan nama internal pendek untuk merujuk pada dirinya sendiri, sambil memberikan nama panjang yang tidak bertentangan untuk pengguna eksternal:
Pada contoh di atas kita dapat melakukan hal yang sama dengan nama eksternal, tetapi itu akan terlalu sulit (dan lebih lambat).
(Cara lain untuk merujuk pada dirinya sendiri adalah menggunakan
arguments.callee
, yang masih relatif lama, dan tidak didukung dalam mode ketat.)Jauh di lubuk hati, JavaScript memperlakukan kedua pernyataan secara berbeda. Ini adalah deklarasi fungsi:
abc
di sini didefinisikan di mana-mana dalam lingkup saat ini:Juga, ia mengangkat melalui
return
pernyataan:Ini adalah ekspresi fungsi:
xyz
di sini didefinisikan dari sudut penugasan:Deklarasi fungsi vs. ekspresi fungsi adalah alasan sebenarnya mengapa ada perbedaan yang ditunjukkan oleh Greg.
Fakta menyenangkan:
Secara pribadi, saya lebih suka deklarasi "fungsi ekspresi" karena dengan cara ini saya dapat mengontrol visibilitas. Ketika saya mendefinisikan fungsi suka
Saya tahu bahwa saya mendefinisikan fungsi secara lokal. Ketika saya mendefinisikan fungsi suka
Saya tahu bahwa saya mendefinisikannya secara global asalkan saya tidak mendefinisikan
abc
di mana pun dalam rantai cakupan. Gaya definisi ini tahan walaupun digunakan di dalameval()
. Sedangkan definisinyatergantung pada konteks dan dapat membuat Anda menebak di mana sebenarnya didefinisikan, terutama dalam kasus
eval()
- jawabannya adalah: Tergantung pada browser.sumber
var abc = function(){}; console.log(abc.name);
tidak menghasilkan""
lagi, tetapi"abc"
sebaliknya.Berikut ini rundown pada formulir standar yang membuat fungsi: (Awalnya ditulis untuk pertanyaan lain, tetapi diadaptasi setelah dipindahkan ke pertanyaan kanonik.)
Ketentuan:
Daftar cepat:
Deklarasi Fungsi
"Anonim"
function
Ekspresi (yang terlepas dari istilah tersebut, terkadang membuat fungsi dengan nama)Bernama
function
EkspresiPenginisialisasi Fungsi Accessor (ES5 +)
Ekspresi Fungsi Panah (ES2015 +) (yang, seperti ekspresi fungsi anonim, tidak melibatkan nama eksplisit, namun dapat membuat fungsi dengan nama)
Deklarasi Metode di Object Inisialisasi (ES2015 +)
Konstruktor dan Deklarasi Metode dalam
class
(ES2015 +)Deklarasi Fungsi
Bentuk pertama adalah deklarasi fungsi , yang terlihat seperti ini:
Deklarasi fungsi adalah deklarasi ; itu bukan pernyataan atau ungkapan. Dengan demikian, Anda tidak mengikutinya dengan
;
(meskipun melakukannya tidak berbahaya).Deklarasi fungsi diproses ketika eksekusi memasuki konteks di mana ia muncul, sebelumnya kode langkah-demi-langkah dijalankan. Fungsi yang dibuatnya diberi nama yang tepat (
x
dalam contoh di atas), dan nama itu dimasukkan ke dalam lingkup di mana deklarasi muncul.Karena diproses sebelum kode langkah-demi-langkah dalam konteks yang sama, Anda dapat melakukan hal-hal seperti ini:
Sampai ES2015, spec tidak menutupi apa yang mesin JavaScript harus dilakukan jika Anda menempatkan sebuah deklarasi fungsi di dalam struktur pengendalian seperti
try
,if
,switch
,while
, dll, seperti ini:Dan karena mereka sudah diproses sebelumnya kode langkah-demi-langkah dijalankan, sulit untuk mengetahui apa yang harus dilakukan ketika mereka berada dalam struktur kontrol.
Meskipun melakukan ini tidak ditentukan sampai ES2015, itu adalah ekstensi yang diijinkan untuk mendukung deklarasi fungsi dalam blok. Sayangnya (dan mau tidak mau), mesin yang berbeda melakukan hal yang berbeda.
Pada ES2015, spesifikasi mengatakan apa yang harus dilakukan. Sebenarnya, ini memberikan tiga hal terpisah untuk dilakukan:
Aturan untuk mode longgar rumit, tetapi dalam mode ketat , deklarasi fungsi dalam blok mudah: Mereka lokal ke blok (mereka memiliki ruang lingkup blok , yang juga baru di ES2015), dan mereka diangkat ke atas dari blok. Begitu:
function
Ekspresi "Anonim"Bentuk umum kedua disebut ekspresi fungsi anonim :
Seperti semua ekspresi, itu dievaluasi ketika dicapai dalam pelaksanaan kode langkah demi langkah.
Di ES5, fungsi yang dibuat ini tidak memiliki nama (anonim). Dalam ES2015, fungsi tersebut diberi nama jika mungkin dengan menyimpulkannya dari konteks. Pada contoh di atas, namanya akan
y
. Hal serupa dilakukan ketika fungsinya adalah nilai dari initializer properti. (Untuk perincian tentang kapan ini terjadi dan aturannya, cariSetFunctionName
dalam spesifikasi - itu muncul di semua tempat.)function
Ekspresi BernamaBentuk ketiga adalah ekspresi fungsi bernama ("NFE"):
Fungsi yang dibuat ini memiliki nama yang tepat (
w
dalam hal ini). Seperti semua ekspresi, ini dievaluasi ketika tercapai dalam langkah-demi-langkah pelaksanaan kode. Nama fungsi tidak ditambahkan ke ruang lingkup di mana ekspresi muncul; nama berada dalam lingkup fungsi itu sendiri:Perhatikan bahwa NFE sering menjadi sumber bug untuk implementasi JavaScript. IE8 dan sebelumnya, misalnya, menangani NFE sepenuhnya salah , menciptakan dua fungsi yang berbeda pada dua waktu yang berbeda. Versi awal Safari juga memiliki masalah. Berita baiknya adalah bahwa versi browser saat ini (IE9 dan yang lebih baru, Safari saat ini) tidak lagi memiliki masalah itu. (Tetapi pada saat penulisan ini, sayangnya, IE8 masih digunakan secara luas, dan menggunakan NFE dengan kode untuk web secara umum masih bermasalah.)
Penginisialisasi Fungsi Accessor (ES5 +)
Terkadang fungsi dapat menyelinap masuk tanpa disadari; itulah yang terjadi dengan fungsi accessor . Ini sebuah contoh:
Perhatikan bahwa ketika saya menggunakan fungsi, saya tidak menggunakan
()
! Itu karena ini merupakan fungsi pengakses untuk sebuah properti. Kami mendapatkan dan mengatur properti dengan cara biasa, tetapi di balik layar, fungsinya disebut.Anda juga dapat membuat accessor fungsi dengan
Object.defineProperty
,Object.defineProperties
, dan argumen kedua kurang dikenal untukObject.create
.Ekspresi Fungsi Panah (ES2015 +)
ES2015 memberi kita fungsi panah . Ini salah satu contohnya:
Lihat
n => n * 2
benda itu bersembunyi dimap()
telepon? Itu sebuah fungsi.Beberapa hal tentang fungsi panah:
Mereka tidak punya sendiri
this
. Sebaliknya, mereka dekat selama inithis
dari konteks di mana mereka didefinisikan. (Mereka juga menutuparguments
dan, jika relevansuper
,.) Ini berarti bahwa dithis
dalam mereka sama dengan dithis
mana mereka diciptakan, dan tidak dapat diubah.Seperti yang Anda perhatikan di atas, Anda tidak menggunakan kata kunci
function
; sebaliknya, Anda gunakan=>
.The
n => n * 2
contoh di atas merupakan salah satu bentuk dari mereka. Jika Anda memiliki beberapa argumen untuk melewati fungsi, Anda menggunakan parens:(Ingat yang
Array#map
melewati entri sebagai argumen pertama, dan indeks sebagai argumen kedua.)Dalam kedua kasus, tubuh fungsi hanyalah sebuah ekspresi; nilai pengembalian fungsi akan secara otomatis menjadi hasil dari ekspresi itu (Anda tidak menggunakan eksplisit
return
).Jika Anda melakukan lebih dari sekedar satu ekspresi, gunakan
{}
dan eksplisitreturn
(jika Anda perlu mengembalikan nilai), seperti biasa:Versi tanpa
{ ... }
disebut fungsi panah dengan tubuh ekspresi atau tubuh ringkas . (Juga: Fungsi panah ringkas .) Yang dengan{ ... }
mendefinisikan tubuh adalah fungsi panah dengan tubuh fungsi . (Juga: Fungsi panah verbose .)Deklarasi Metode di Object Inisialisasi (ES2015 +)
ES2015 memungkinkan bentuk pendek menyatakan properti yang referensi fungsi yang disebut definisi metode ; terlihat seperti ini:
yang hampir setara di ES5 dan sebelumnya adalah:
perbedaannya (selain verbositas) adalah suatu metode dapat digunakan
super
, tetapi suatu fungsi tidak bisa. Jadi misalnya, jika Anda memiliki objek yang didefinisikan (katakanlah)valueOf
menggunakan sintaksis metode, itu bisa digunakansuper.valueOf()
untuk mendapatkan nilaiObject.prototype.valueOf
akan kembali (sebelum mungkin melakukan sesuatu yang lain dengan itu), sedangkan versi ES5 harus melakukanObject.prototype.valueOf.call(this)
sebaliknya.Itu juga berarti bahwa metode memiliki referensi ke objek yang didefinisikan, jadi jika objek itu bersifat sementara (misalnya, Anda meneruskannya menjadi
Object.assign
salah satu objek sumber), sintaksis metode dapat berarti bahwa objek tersebut dipertahankan dalam memori ketika sebaliknya bisa saja sampah dikumpulkan (jika mesin JavaScript tidak mendeteksi situasi itu dan menanganinya jika tidak ada metode yang digunakansuper
).Konstruktor dan Deklarasi Metode dalam
class
(ES2015 +)ES2015 membawa kita
class
sintaks, termasuk konstruktor dan metode yang dideklarasikan:Ada dua deklarasi fungsi di atas: Satu untuk konstruktor, yang mendapatkan nama
Person
, dan satu untukgetFullName
, yang merupakan fungsi yang ditugaskan untukPerson.prototype
.sumber
w
itu diabaikan begitu saja?Berbicara tentang konteks global, keduanya,
var
pernyataan dan aFunctionDeclaration
pada akhirnya akan membuat properti yang tidak dapat dihapus pada objek global, tetapi nilai keduanya dapat ditimpa .Perbedaan halus antara dua cara adalah bahwa ketika proses Instansiasi Variabel berjalan (sebelum eksekusi kode aktual) semua pengidentifikasi yang dideklarasikan dengan
var
akan diinisialisasi denganundefined
, dan yang digunakan olehFunctionDeclaration
's akan tersedia sejak saat itu, misalnya:Penugasan
bar
FunctionExpression
berlangsung hingga runtime.Properti global yang dibuat oleh a
FunctionDeclaration
dapat ditimpa tanpa masalah sama seperti nilai variabel, misalnya:Perbedaan jelas lainnya antara kedua contoh Anda adalah bahwa fungsi pertama tidak memiliki nama, tetapi yang kedua memiliki itu, yang dapat sangat berguna saat debugging (yaitu memeriksa tumpukan panggilan).
Tentang contoh pertama yang diedit (
foo = function() { alert('hello!'); };
), ini adalah tugas yang belum dideklarasikan, saya sangat menyarankan Anda untuk selalu menggunakanvar
kata kunci.Dengan penugasan, tanpa
var
pernyataan, jika pengidentifikasi yang direferensikan tidak ditemukan dalam rantai lingkup, itu akan menjadi properti yang dapat dihapus dari objek global.Juga, tugas yang tidak diumumkan melemparkan
ReferenceError
ECMAScript 5 di bawah Mode Ketat .A harus membaca:
Catatan : Jawaban ini telah digabungkan dari pertanyaan lain , di mana keraguan utama dan kesalahpahaman dari OP adalah bahwa pengidentifikasi dideklarasikan dengan a
FunctionDeclaration
, tidak dapat ditimpa yang tidak demikian.sumber
Dua cuplikan kode yang Anda poskan di sana akan, untuk hampir semua tujuan, berperilaku dengan cara yang sama.
Namun, perbedaan dalam perilaku adalah bahwa dengan varian pertama (
var functionOne = function() {}
), fungsi itu hanya dapat dipanggil setelah titik itu dalam kode.Dengan varian kedua (
function functionTwo()
), fungsi tersedia untuk kode yang berjalan di atas di mana fungsi tersebut dinyatakan.Ini karena dengan varian pertama, fungsi ditugaskan ke variabel
foo
saat run time. Di yang kedua, fungsi ditugaskan untuk pengidentifikasi itufoo
,, pada waktu parse.Lebih banyak informasi teknis
JavaScript memiliki tiga cara untuk mendefinisikan fungsi.
eval()
, yang memiliki masalah.sumber
Penjelasan yang lebih baik untuk jawaban Greg
Kenapa tidak ada kesalahan? Kami selalu diajarkan bahwa ekspresi dieksekusi dari atas ke bawah (??)
Karena:
Ini berarti bahwa kode seperti ini:
Perhatikan bahwa bagian penugasan deklarasi tidak diangkat. Hanya namanya yang diangkat.
Tetapi dalam kasus dengan deklarasi fungsi, seluruh fungsi tubuh akan diangkat juga :
sumber
Komentator lain telah membahas perbedaan semantik dari dua varian di atas. Saya ingin mencatat perbedaan gaya: Hanya variasi "tugas" yang dapat menetapkan properti objek lain.
Saya sering membuat modul JavaScript dengan pola seperti ini:
Dengan pola ini, semua fungsi publik Anda akan menggunakan penugasan, sedangkan fungsi pribadi Anda menggunakan deklarasi.
(Perhatikan juga bahwa penugasan harus meminta titik koma setelah pernyataan, sedangkan deklarasi melarangnya.)
sumber
var foo = function(){...}
sintaks bahkan untuk variabel pribadi.function window.onload() {}
adalah suatu hal.)Ilustrasi kapan memilih metode pertama daripada yang kedua adalah ketika Anda harus menghindari mengesampingkan definisi fungsi sebelumnya.
Dengan
, definisi ini
myfunction
akan menggantikan definisi sebelumnya, karena akan dilakukan pada waktu parse.Sementara
melakukan pekerjaan yang benar untuk mendefinisikan
myfunction
hanya ketikacondition
bertemu.sumber
var myFunc = null;
luar loop, atau di luar blok if / elseif / else. Kemudian Anda dapat menetapkan fungsi yang berbeda secara kondisional ke variabel yang sama. Di JS, itu adalah konvensi yang lebih baik untuk menetapkan nilai yang hilang ke nol, lalu ke undefined. Karena itu, Anda harus mendeklarasikan myFunction sebagai null terlebih dahulu, lalu menetapkannya nanti, dengan syarat.Alasan penting adalah untuk menambahkan satu dan hanya satu variabel sebagai "Root" dari namespace Anda ...
atau
Ada banyak teknik untuk namespacing. Ini menjadi lebih penting dengan banyaknya modul JavaScript yang tersedia.
Lihat juga Bagaimana cara mendeklarasikan namespace dalam JavaScript?
sumber
Mengangkat adalah tindakan penerjemah JavaScript untuk memindahkan semua deklarasi variabel dan fungsi ke bagian atas lingkup saat ini.
Namun, hanya deklarasi aktual yang diangkat. dengan meninggalkan tugas di mana mereka berada.
Variabel
Javascript disebut bahasa yang diketik secara longgar. Yang berarti variabel Javascript dapat menyimpan nilai dari Tipe Data apa pun . Javascript secara otomatis menangani perubahan tipe variabel berdasarkan nilai / literal yang diberikan selama runtime.
Fungsi
Nilai pengembalian default fungsi adalah ' tidak terdefinisi ', Nilai default deklarasi variabel juga 'tidak terdefinisi'
Deklarasi Fungsi
Ekspresi fungsi
Fungsi yang ditugaskan ke variabel Contoh:
javascript diartikan sebagai
Anda dapat memeriksa deklarasi fungsi, tes ekspresi menggunakan browser yang berbeda
jsperf Test Runner
ES5 Constructor Function Classes : Objek fungsi dibuat menggunakan Function.prototype.bind
JavaScript memperlakukan fungsi sebagai objek kelas satu, jadi sebagai objek, Anda dapat menetapkan properti ke suatu fungsi.
ES6 memperkenalkan fungsi Panah : Ekspresi fungsi panah memiliki sintaks yang lebih pendek, mereka paling cocok untuk fungsi non-metode, dan mereka tidak dapat digunakan sebagai konstruktor.
sumber
Saya menambahkan jawaban saya sendiri hanya karena semua orang telah membahas bagian mengangkat secara menyeluruh.
Saya bertanya-tanya tentang jalan mana yang lebih baik untuk waktu yang lama sekarang, dan terima kasih kepada http://jsperf.com sekarang saya tahu :)
Deklarasi fungsi lebih cepat, dan itulah yang benar-benar penting di web dev, kan? ;)
sumber
Deklarasi fungsi dan ekspresi fungsi yang ditetapkan ke variabel berperilaku sama setelah pengikatan dibuat.
Namun ada perbedaan pada bagaimana dan kapan objek fungsi sebenarnya terkait dengan variabelnya. Perbedaan ini disebabkan oleh mekanisme yang disebut pengangkat variabel dalam JavaScript.
Pada dasarnya, semua deklarasi fungsi dan deklarasi variabel diangkat ke bagian atas fungsi tempat deklarasi terjadi (inilah sebabnya kami mengatakan bahwa JavaScript memiliki cakupan fungsi ).
Ketika deklarasi fungsi diangkat, fungsi tubuh "mengikuti" sehingga ketika fungsi tubuh dievaluasi, variabel akan segera terikat ke objek fungsi.
Ketika deklarasi variabel diangkat, inisialisasi tidak mengikuti, tetapi "tertinggal". Variabel diinisialisasi
undefined
pada awal fungsi tubuh, dan akan diberi nilai di lokasi aslinya dalam kode. (Sebenarnya, itu akan diberi nilai di setiap lokasi di mana deklarasi variabel dengan nama yang sama terjadi.)Urutan pengangkatan juga penting: deklarasi fungsi didahulukan dari deklarasi variabel dengan nama yang sama, dan deklarasi fungsi terakhir diutamakan daripada deklarasi fungsi sebelumnya dengan nama yang sama.
Beberapa contoh...
Variabel
foo
yang mengangkat ke atas fungsi, diinisialisasi keundefined
, sehingga!foo
adalahtrue
, begitufoo
ditugaskan10
. Bagianfoo
luarbar
ruang lingkup tidak memainkan peran dan tidak tersentuh.Deklarasi fungsi didahulukan dari deklarasi variabel, dan deklarasi fungsi terakhir "menempel".
Dalam contoh
a
ini diinisialisasi dengan objek fungsi yang dihasilkan dari mengevaluasi deklarasi fungsi kedua, dan kemudian ditugaskan4
.Di sini deklarasi fungsi diangkat terlebih dahulu, mendeklarasikan dan menginisialisasi variabel
a
. Selanjutnya, variabel ini ditugaskan10
. Dengan kata lain: tugas tidak ditugaskan ke variabel luara
.sumber
Contoh pertama adalah deklarasi fungsi:
Contoh kedua adalah ekspresi fungsi:
Perbedaan utama adalah bagaimana mereka diangkat (diangkat dan dideklarasikan). Dalam contoh pertama, deklarasi seluruh fungsi diangkat. Dalam contoh kedua hanya var 'abc' yang diangkat, nilainya (fungsi) akan tidak ditentukan, dan fungsi itu sendiri tetap pada posisi yang dideklarasikan.
Untuk membuatnya lebih sederhana:
Untuk mempelajari lebih lanjut tentang topik ini, saya sangat merekomendasikan Anda tautan ini
sumber
Dalam hal biaya pemeliharaan kode, fungsi-fungsi yang disebutkan lebih disukai:
Saya menduga lebih banyak PROS untuk fungsi yang disebutkan diikuti. Dan apa yang terdaftar sebagai keuntungan dari fungsi-fungsi yang disebutkan adalah kerugian bagi yang anonim.
Secara historis, fungsi anonim muncul dari ketidakmampuan JavaScript sebagai bahasa untuk mendaftar anggota dengan fungsi bernama:
sumber
Dalam istilah ilmu komputer, kita berbicara tentang fungsi anonim dan fungsi bernama. Saya pikir perbedaan yang paling penting adalah bahwa fungsi anonim tidak terikat pada nama, maka fungsi anonim namanya. Dalam JavaScript, ini adalah objek kelas satu yang secara dinamis dideklarasikan saat runtime.
Untuk informasi lebih lanjut tentang fungsi anonim dan kalkulus lambda, Wikipedia adalah awal yang baik ( http://en.wikipedia.org/wiki/Anonymous_function ).
sumber
Saya menggunakan pendekatan variabel dalam kode saya untuk alasan yang sangat spesifik, teorinya telah dibahas secara abstrak di atas, tetapi sebuah contoh mungkin membantu beberapa orang seperti saya, dengan keahlian JavaScript terbatas.
Saya memiliki kode yang harus saya jalankan dengan 160 merek yang dirancang secara independen. Sebagian besar kode ada di file bersama, tetapi hal-hal khusus branding ada di file terpisah, satu untuk setiap branding.
Beberapa merek membutuhkan fungsi tertentu, dan beberapa tidak. Kadang-kadang saya harus menambahkan fungsi baru untuk melakukan hal-hal khusus branding baru. Saya senang mengubah kode bersama, tapi saya tidak mau harus mengubah semua 160 set file branding.
Dengan menggunakan sintaks variabel, saya dapat mendeklarasikan variabel (fungsi pointer pada dasarnya) dalam kode bersama dan menetapkan fungsi stub trivial, atau setel ke nol.
Satu atau dua merek yang membutuhkan implementasi fungsi tertentu kemudian dapat mendefinisikan versi fungsi mereka dan menetapkan ini ke variabel jika mereka mau, dan sisanya tidak melakukan apa-apa. Saya dapat menguji fungsi null sebelum saya menjalankannya dalam kode bersama.
Dari komentar orang di atas, saya mengumpulkan mungkin untuk mendefinisikan kembali fungsi statis juga, tapi saya pikir solusi variabelnya bagus dan jelas.
sumber
Jawaban Greg sudah cukup baik, tetapi saya masih ingin menambahkan sesuatu yang saya pelajari tadi dengan memperhatikan jawaban Douglas Crockford video .
Ekspresi fungsi:
Pernyataan fungsi:
Pernyataan fungsi hanyalah singkatan untuk
var
pernyataan dengan afunction
nilai.Begitu
meluas ke
Yang berkembang lebih jauh ke:
Dan mereka berdua diangkat ke atas kode.
sumber
Ada empat perbandingan penting antara dua deklarasi fungsi yang berbeda seperti yang tercantum di bawah ini.
Berikut ini berfungsi karena
function add()
dicakup ke blok terdekat:Berikut ini tidak berfungsi karena variabel dipanggil sebelum nilai fungsi ditugaskan ke variabel
add
.Kode di atas identik dalam fungsionalitas dengan kode di bawah ini. Perhatikan bahwa penetapan secara eksplisit
add = undefined
tidak perlu karena hanya melakukanvar add;
adalah sama persis denganvar add=undefined
.Berikut ini tidak berfungsi karena
var add=
mengunggulkanfunction add()
.Nama fungsi
function thefuncname(){}
adalah thefuncname ketika dinyatakan dengan cara ini.Jika tidak, jika suatu fungsi dinyatakan sebagai
function(){}
, fungsi .name adalah variabel pertama yang digunakan untuk menyimpan fungsi.Jika tidak ada variabel yang diatur ke fungsi, maka nama fungsi adalah string kosong (
""
).Terakhir, ketika variabel fungsi ditugaskan untuk awalnya menetapkan nama, variabel berturut-turut diatur ke fungsi tidak mengubah nama.
Di Google V8 dan Spidermonkey Firefox mungkin ada beberapa perbedaan kompilasi JIST mikrodetik, tetapi pada akhirnya hasilnya sama persis. Untuk membuktikan ini, mari kita periksa efisiensi JSPerf di microbenchmarks dengan membandingkan kecepatan dua cuplikan kode kosong. The tes JSPerf yang ditemukan di sini . Dan, tes jsben.ch ditemukan di sini . Seperti yang Anda lihat, ada perbedaan nyata ketika seharusnya tidak ada. Jika Anda benar-benar orang aneh kinerja seperti saya, maka mungkin lebih bernilai saat Anda mencoba mengurangi jumlah variabel dan fungsi dalam lingkup dan terutama menghilangkan polimorfisme (seperti menggunakan variabel yang sama untuk menyimpan dua jenis yang berbeda).
Ketika Anda menggunakan
var
kata kunci untuk mendeklarasikan variabel, Anda kemudian dapat menetapkan kembali nilai yang berbeda untuk variabel seperti itu.Namun, ketika kita menggunakan pernyataan const, referensi variabel menjadi tidak berubah. Ini berarti bahwa kami tidak dapat menetapkan nilai baru ke variabel. Harap dicatat, bagaimanapun, bahwa ini tidak membuat isi variabel tidak berubah: jika Anda melakukannya
const arr = []
, maka Anda masih bisa melakukannyaarr[10] = "example"
. Hanya melakukan sesuatu sepertiarr = "new value"
atauarr = []
akan melakukan kesalahan seperti yang terlihat di bawah ini.Menariknya, jika kita mendeklarasikan variabel sebagai
function funcName(){}
, maka immutabilitas variabel sama dengan mendeklarasikannyavar
.Apa Itu "Blok Terdekat"
"Blok terdekat" adalah "fungsi" terdekat, (termasuk fungsi asinkron, fungsi generator, dan fungsi generator asinkron). Namun, yang menarik, seorang
function functionName() {}
berperilaku sepertivar functionName = function() {}
ketika di blok non-penutupan untuk barang-barang di luar kata penutupan. Mengamati.var add=function(){}
function add(){}
if
,else
,for
,while
,try
/catch
/finally
,switch
,do
/while
,with
)var add=function()
function add()
sumber
@EugeneLazutkin memberikan contoh di mana ia menamai fungsi yang ditugaskan untuk dapat digunakan
shortcut()
sebagai referensi internal untuk dirinya sendiri. John Resig memberikan contoh lain - menyalin fungsi rekursif yang ditugaskan ke objek lain dalam Learning Advanced Javascript-nya tutorial . Meskipun menugaskan fungsi ke properti tidak sepenuhnya merupakan pertanyaan di sini, saya sarankan untuk secara aktif mencoba tutorialnya - jalankan kode dengan mengklik tombol di sudut kanan atas, dan klik dua kali kode untuk mengedit sesuai keinginan Anda.Contoh dari tutorial: panggilan rekursif dalam
yell()
:Tes gagal ketika objek ninja asli dihapus. (halaman 13)
Jika Anda menyebutkan fungsi yang akan dipanggil secara rekursif, tes akan berlalu. (halaman 14)
sumber
Perbedaan lain yang tidak disebutkan dalam jawaban lain adalah jika Anda menggunakan fungsi anonim
dan menggunakannya sebagai konstruktor seperti pada
maka
one.constructor.name
tidak akan didefinisikan.Function.name
tidak standar tetapi didukung oleh Firefox, Chrome, browser lain yang diturunkan dari Webkit dan IE 9+.Dengan
adalah mungkin untuk mengambil nama konstruktor sebagai string
two.constructor.name
.sumber
Yang pertama (function doSomething (x)) harus menjadi bagian dari notasi objek.
Yang kedua (
var doSomething = function(x){ alert(x);}
) hanya membuat fungsi anonim dan menugaskannya ke variabeldoSomething
,. Jadi doSomething () akan memanggil fungsi.Anda mungkin ingin tahu apa fungsi deklarasi dan ekspresi fungsi .
Deklarasi fungsi mendefinisikan variabel fungsi yang dinamai tanpa memerlukan penugasan variabel. Deklarasi fungsi terjadi sebagai konstruksi mandiri dan tidak dapat disarangkan dalam blok non-fungsi.
Dalam kondisi di atas nama fungsi terlihat dalam ruang lingkup dan ruang lingkup induknya (jika tidak maka tidak akan terjangkau).
Dan dalam ekspresi fungsi
Ekspresi fungsi mendefinisikan fungsi sebagai bagian dari sintaks ekspresi yang lebih besar (biasanya penugasan variabel). Fungsi yang didefinisikan melalui fungsi ekspresi dapat dinamai atau anonim. Ekspresi fungsi tidak boleh dimulai dengan "fungsi".
sumber
Saya mencantumkan perbedaan di bawah ini:
Deklarasi fungsi dapat ditempatkan di mana saja dalam kode. Bahkan jika itu dipanggil sebelum definisi muncul dalam kode, itu dieksekusi ketika deklarasi fungsi dilakukan ke memori atau dengan cara itu diangkat, sebelum kode lain di halaman mulai dieksekusi.
Lihatlah fungsi di bawah ini:
Ini karena, selama eksekusi, sepertinya: -
Ekspresi fungsi, jika tidak didefinisikan sebelum memanggilnya, akan menghasilkan kesalahan. Juga, di sini definisi fungsi itu sendiri tidak dipindahkan ke atas atau dikomit ke memori seperti dalam deklarasi fungsi. Tetapi variabel yang kita tetapkan fungsi akan diangkat dan tidak terdefinisi akan ditugaskan untuk itu.
Fungsi yang sama menggunakan ekspresi fungsi:
Ini karena selama eksekusi, sepertinya:
Tidak aman untuk menulis deklarasi fungsi dalam blok non-fungsi seperti jika karena mereka tidak akan dapat diakses.
Ekspresi fungsi yang dinamai seperti di bawah ini, mungkin tidak berfungsi di browser Internet Explorer sebelum versi 9.
sumber
Jika Anda akan menggunakan fungsi-fungsi itu untuk membuat objek, Anda akan mendapatkan:
sumber
console.log(objectOne.__proto__);
mencetak "functionOne {}" di konsol saya. Adakah gagasan mengapa ini bisa terjadi?Sehubungan dengan argumen "fungsi yang disebutkan muncul dalam tumpukan jejak", mesin JavaScript modern sebenarnya cukup mampu mewakili fungsi anonim.
Pada tulisan ini, V8, SpiderMonkey, Chakra, dan Nitro selalu merujuk ke fungsi yang dinamai dengan nama mereka. Mereka hampir selalu merujuk ke fungsi anonim oleh pengenalnya jika ada.
SpiderMonkey dapat mengetahui nama fungsi anonim yang dikembalikan dari fungsi lain. Sisanya tidak bisa.
Jika Anda benar-benar ingin iterator dan panggilan balik sukses Anda muncul di jejak, Anda bisa menyebutkannya juga ...
Tetapi sebagian besar itu tidak perlu ditekankan.
Harness ( Biola )
V8
Monyet laba-laba
Cakra
Nitro
sumber
Dalam JavaScript ada dua cara untuk membuat fungsi:
Deklarasi fungsi:
Ini sangat mendasar, cukup jelas, digunakan dalam banyak bahasa dan standar di seluruh rumpun bahasa C. Kami mendeklarasikan fungsi yang mendefinisikannya dan menjalankannya dengan memanggilnya.
Yang harus Anda ketahui adalah bahwa fungsi sebenarnya adalah objek dalam JavaScript; secara internal kami telah membuat objek untuk fungsi di atas dan memberinya nama yang disebut fn atau referensi ke objek disimpan dalam fn. Fungsi adalah objek dalam JavaScript; sebuah instance dari fungsi sebenarnya adalah instance objek.
Ekspresi fungsi:
JavaScript memiliki fungsi kelas satu, yaitu membuat fungsi dan menetapkannya ke variabel seperti halnya Anda membuat string atau angka dan menetapkannya ke variabel. Di sini, variabel fn ditugaskan ke suatu fungsi. Alasan untuk konsep ini adalah fungsi adalah objek dalam JavaScript; fn menunjuk ke instance objek dari fungsi di atas. Kami telah menginisialisasi fungsi dan menugaskannya ke variabel. Itu tidak menjalankan fungsi dan menetapkan hasilnya.
Referensi: Sintaks deklarasi fungsi JavaScript: var fn = function () {} vs function fn () {}
sumber
var fn = function fn() {...}
?Keduanya berbeda cara mendefinisikan suatu fungsi. Perbedaannya adalah bagaimana browser mengartikan dan memuatnya ke dalam konteks eksekusi.
Kasus pertama adalah ekspresi fungsi yang dimuat hanya ketika penerjemah mencapai garis kode itu. Jadi jika Anda melakukannya seperti berikut, Anda akan mendapatkan kesalahan bahwa functionOne bukan fungsi .
Alasannya adalah bahwa pada baris pertama tidak ada nilai yang diberikan ke functionOne, dan karenanya tidak terdefinisi. Kami mencoba menyebutnya sebagai fungsi, dan karenanya kami mendapatkan kesalahan.
Pada baris kedua, kami memberikan referensi fungsi anonim ke functionOne.
Kasus kedua adalah deklarasi fungsi yang dimuat sebelum kode dijalankan. Jadi, jika Anda menyukai yang berikut ini, Anda tidak akan mendapatkan kesalahan apa pun ketika deklarasi dimuat sebelum eksekusi kode.
sumber
Tentang kinerja:
Versi baru
V8
memperkenalkan beberapa optimasi di bawah tenda dan begitu jugaSpiderMonkey
.Hampir tidak ada perbedaan sekarang antara ekspresi dan deklarasi.
Ekspresi fungsi tampaknya lebih cepat sekarang.
Chrome 62.0.3202
FireFox 55
Chrome Canary 63.0.3225
Firefox Chrome Canary Chrome
sumber
Mereka sangat mirip dengan beberapa perbedaan kecil, yang pertama adalah variabel yang ditugaskan untuk fungsi anonim (Deklarasi Fungsi) dan yang kedua adalah cara normal untuk membuat fungsi dalam JavaScript (Deklarasi fungsi Anonim), keduanya memiliki penggunaan, kontra dan pro :
1. Ekspresi Fungsi
Tetapkan variabel ke suatu fungsi, berarti tidak ada Hoisting, seperti yang kita tahu fungsi dalam JavaScript dapat Hoist, berarti mereka dapat dipanggil sebelum dideklarasikan, sementara variabel perlu dideklarasikan sebelum mendapatkan akses ke mereka, jadi berarti dalam hal ini kita tidak bisa mengakses fungsi sebelum di mana itu dinyatakan, juga itu bisa menjadi cara Anda menulis fungsi Anda, untuk fungsi yang mengembalikan fungsi lain, deklarasi semacam ini masuk akal, juga di ECMA6 & di atas Anda dapat menetapkan ini ke fungsi panah yang dapat digunakan untuk memanggil fungsi anonim, juga cara mendeklarasikan ini adalah cara yang lebih baik untuk membuat fungsi Konstruktor dalam JavaScript.
2. Deklarasi Fungsi
Ini adalah cara normal memanggil fungsi dalam JavaScript, fungsi ini dapat dipanggil sebelum Anda bahkan mendeklarasikannya seperti pada JavaScript semua fungsi di-Hoisted, tetapi jika Anda memiliki 'gunakan ketat' ini tidak akan Hoist seperti yang diharapkan, itu cara yang baik untuk memanggil semua fungsi normal yang tidak berbaris besar dan tidak pula fungsi konstruktor.
Juga, jika Anda memerlukan info lebih lanjut tentang cara kerja mengangkat dalam JavaScript, kunjungi tautan di bawah:
https://developer.mozilla.org/en-US/docs/Glossary/Hoisting
sumber
...also this way of declaring is a better way to create Constructor functions in JavaScript
Tolong jelaskan, saya penasaran!Ini hanya dua cara yang mungkin untuk mendeklarasikan fungsi, dan dengan cara kedua, Anda dapat menggunakan fungsi sebelum deklarasi.
sumber
new Function()
dapat digunakan untuk melewatkan fungsi tubuh dalam sebuah string. Dan karenanya ini dapat digunakan untuk membuat fungsi dinamis. Juga melewati skrip tanpa menjalankan skrip.sumber