Rumah  >  Artikel  >  hujung hadapan web  >  Analisis ringkas tentang perbezaan antara pengisytiharan fungsi dan ekspresi fungsi dalam kemahiran JavaScript_javascript

Analisis ringkas tentang perbezaan antara pengisytiharan fungsi dan ekspresi fungsi dalam kemahiran JavaScript_javascript

WBOY
WBOYasal
2016-05-16 16:07:261020semak imbas

Saya masih ingat semasa saya menemu duga sebagai pelatih di Tencent, penemuduga bertanyakan soalan ini kepada saya.

Salin kod Kod adalah seperti berikut:

//Apakah perbezaan antara dua kaedah pengisytiharan berikut

fungsi foo(){};

bar var = function foo(){}; 

Pada mulanya saya hanya mengetahui dua kaedah pengisytiharan: pengisytiharan fungsi dan ungkapan fungsi saya tidak dapat menerangkan perbezaan khusus. Saya kebetulan melihat sebuah buku mengenai topik ini baru-baru ini dan ingin meringkaskannya.

Dalam ECMAScript, terdapat dua kaedah yang paling biasa digunakan untuk mencipta objek fungsi, iaitu menggunakan ungkapan fungsi atau menggunakan pengisytiharan fungsi. Dalam hal ini, spesifikasi ECMAScript menjelaskan bahawa pengisytiharan fungsi mesti sentiasa mempunyai pengecam (Pengecam), iaitu apa yang kita panggil nama fungsi, dan ungkapan fungsi boleh ditinggalkan.

Pengisytiharan fungsi:

Salin kod Kod adalah seperti berikut:

pengecam fungsi (pilihan FormalParameterList){ FunctionBody }

Proses penghuraian pengisytiharan fungsi adalah seperti berikut:

 1. Buat objek Fungsi baharu, FormalParameterList menentukan parameter dan FunctionBody menentukan badan fungsi. Menggunakan rantai skop dalam persekitaran yang sedang berjalan sebagai skopnya.

 2. Cipta atribut bernama Pengecam untuk objek pembolehubah semasa, dengan nilai Result(1).

Ungkapan fungsi:

(Ungkapan fungsi dibahagikan kepada ungkapan fungsi tanpa nama dan dinamakan)

Salin kod Kod adalah seperti berikut:

function Identifier opt(FormalParameterList opt){ FunctionBody } //Berikut ialah ungkapan fungsi bernama

Proses penghuraian bagi ungkapan fungsi yang dinamakan adalah seperti berikut:

1. Cipta Objek baharu
2. Tambahkan Hasil(1) pada bahagian atas rantai skop
3. Cipta objek Function baharu, nyatakan parameter dalam FormalParameterList dan nyatakan badan fungsi dalam FunctionBody. Menggunakan rantai skop dalam persekitaran pelaksanaan yang sedang berjalan sebagai skopnya.
4. Cipta atribut bernama Identifier for Result(1), nilainya ialah Result(3), baca sahaja, tidak boleh dipadamkan
5. Alih keluar Result(1)
daripada rantai skop 6. Keputusan Pulangan(3)

Dokumentasi rasmi sangat sukar dibaca. Ringkasnya, ECMAScript membezakan keduanya melalui konteks: jika function foo(){} ialah sebahagian daripada ungkapan tugasan, ia dianggap sebagai ungkapan fungsi. Dan jika fungsi foo(){} terkandung dalam badan fungsi, atau terletak dalam (peringkat atas) atur cara, ia dihuraikan sebagai pengisytiharan fungsi. Jelas sekali, apabila pengecam ditinggalkan, "ungkapan" hanya boleh menjadi ungkapan.

Salin kod Kod adalah seperti berikut:

function foo(){}; // Pengisytiharan kerana ia adalah sebahagian daripada program

var bar = function foo(){}; // Ungkapan, kerana ia adalah sebahagian daripada ungkapan tugasan (AssignmentExpression)

bar fungsi baharu(){}; // Ungkapan, kerana ia merupakan sebahagian daripada Ungkapan Baharu (NewExpression)

(fungsi(){
Bar fungsi(){}; // Pengisytiharan, kerana ia adalah sebahagian daripada badan fungsi (FunctionBody)
})();

Ada satu lagi situasi:

Salin kod Kod adalah seperti berikut:

(fungsi foo(){})

Kes ini juga merupakan ungkapan fungsi, yang merupakan fungsi yang disertakan dalam sepasang kurungan Dalam konteksnya, () membentuk operator kumpulan dan operator kumpulan hanya boleh mengandungi ungkapan Lagi Contoh:

Salin kod Kod adalah seperti berikut:

function foo(){}; // Pengisytiharan fungsi

(function foo(){}); // Ungkapan fungsi: ambil perhatian bahawa ia disertakan dalam operator kumpulan

cuba {
(var x = 5); // Operator pengelompokan hanya boleh mengandungi ungkapan, bukan pernyataan (var di sini ialah pernyataan)
}
tangkap(err) {
// SyntaxError (kerana "var x = 5" ialah pernyataan, bukan ungkapan - menilai ungkapan mesti mengembalikan nilai, tetapi menilai pernyataan tidak semestinya mengembalikan nilai. - Terjemahan
}

Mari kita bincangkan secara ringkas tentang persamaan dan perbezaan antara pengisytiharan fungsi dan ungkapan fungsi. Terdapat perbezaan yang halus namun penting dalam tingkah laku pengisytiharan dan ungkapan.

Pertama, pengisytiharan fungsi dihuraikan dan dinilai sebelum sebarang ungkapan dihuraikan dan dinilai. Walaupun pengisytiharan ialah baris terakhir dalam kod sumber, ia akan dinilai sebelum ungkapan pertama dalam skop yang sama. Lebih mudah difahami dengan melihat contoh. Dalam contoh berikut, fungsi fn diisytiharkan selepas amaran. Walau bagaimanapun, apabila amaran dilaksanakan, fn sudah ditakrifkan:

Salin kod Kod adalah seperti berikut:

alert(fn()); //Output Helloworld!
fungsi fn() {
kembalikan 'Helloworld!';
}

Untuk meringkaskan secara ringkas, apakah perbezaannya?

1. Pengisytiharan sentiasa dihuraikan pada permulaan skop; 2. Ungkapan dinilai hanya apabila ditemui.


Pengisytiharan fungsi mempunyai satu lagi ciri penting,

iaitu, tingkah laku mengawal pengisytiharan fungsi melalui pernyataan bersyarat tidak diseragamkan, jadi hasil yang berbeza mungkin diperoleh dalam persekitaran yang berbeza

. Iaitu:

// Jangan lakukan ini!
// Pelayar yang berbeza akan mengembalikan hasil yang berbeza,

jika (benar) {
fungsi foo() {
kembali 'dahulu';
}
}
lain {
fungsi foo() {
kembali 'kedua';
}
}
foo();


// Ingat untuk menggunakan ungkapan fungsi dalam kes ini:
var foo;
jika (benar) {
foo = function() {
kembali 'dahulu';
};
}
lain {
foo = function() {
kembali 'kedua';
};
}
foo();


Jadi, apakah peraturan sebenar untuk menggunakan pengisytiharan fungsi?

FunctionDeclaration hanya boleh muncul dalam Program atau FunctionBody. Secara sintaksis, ia tidak boleh muncul di dalam Blok ({ ... }), contohnya, dalam pernyataan if, while, atau for. Kerana Blok hanya boleh mengandungi Pernyataan, tetapi bukan SourceElement seperti FunctionDeclaration.

Sebaliknya, jika anda melihat dengan lebih dekat peraturan penjanaan, anda akan mendapati bahawa satu-satunya cara untuk Ekspresi muncul dalam Blok ialah menjadikannya sebahagian daripada Pernyataan Ungkapan. Walau bagaimanapun, spesifikasi dengan jelas menyatakan bahawa ExpressionStatement tidak boleh bermula dengan fungsi kata kunci. Perkara ini sebenarnya bermakna bahawa FunctionExpression tidak boleh muncul dalam Pernyataan atau Blok (jangan lupa bahawa Blok terdiri daripada Pernyataan).

Disebabkan oleh sekatan di atas, setiap kali fungsi muncul dalam blok (seperti dalam contoh di atas), ia sepatutnya dianggap sebagai ralat sintaks dan bukannya pengisytiharan atau ungkapan fungsi.

 

 Jadi bilakah kita harus menggunakan pengisytiharan fungsi atau ungkapan fungsi? Pengisytiharan fungsi hanya boleh muncul dalam "kod program", yang bermaksud ia hanya boleh muncul dalam badan fungsi lain atau dalam ruang global tidak boleh diberikan kepada pembolehubah atau atribut, atau diluluskan sebagai parameter dalam panggilan fungsi; Contohnya ialah penggunaan pengisytiharan fungsi yang dibenarkan foo(), bar() dan local() semuanya diisytiharkan melalui mod pengisytiharan fungsi:

.

//Persekitaran global
fungsi foo() {}

function local() {
// Persekitaran setempat
Bar fungsi() {}
         bar kembali;
}


Apabila anda tidak boleh menggunakan pengisytiharan fungsi secara sintaksis, anda boleh menggunakan ungkapan fungsi. Contohnya: lulus fungsi sebagai parameter atau tentukan fungsi dalam literal objek:


Salin kod Kod adalah seperti berikut:

// Ini ialah ungkapan fungsi tanpa nama
callMe(fungsi () {

//Luluskan fungsi sebagai parameter
});

// Ini ialah ungkapan fungsi bernama
callMe(function me() {

// Lulus fungsi sebagai parameter, nama fungsi ialah saya
});

// Ungkapan fungsi lain
var myobject = {
Sebut: fungsi () {

// Saya ialah ungkapan fungsi
}
};

Pengetahuan saya terhad, tolong betulkan saya jika ada kesilapan.

Kenyataan:
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn