I've baru-baru ini mulai menjaga orang lain's kode JavaScript. I'm memperbaiki bug, menambahkan fitur, dan juga mencoba untuk merapikan kode dan membuatnya lebih konsisten.
Sebelumnya pengembang menggunakan dua cara menyatakan fungsi dan aku bisa't bekerja keluar jika ada alasan di balik itu atau tidak.
Dua cara tersebut adalah:
var functionOne = function() {
// Some code
};
function functionTwo() {
// Some code
}
Apa alasan untuk menggunakan dua metode yang berbeda dan apa pro dan kontra dari masing-masing? Apakah ada sesuatu yang dapat dilakukan dengan salah satu metode yang dapat't dilakukan dengan lainnya?
Perbedaannya adalah bahwa functionOne
adalah ekspresi fungsi dan sehingga hanya didefinisikan ketika garis itu tercapai, sedangkan saki
adalah deklarasi fungsi dan didefinisikan sesegera sekitarnya fungsi atau script dijalankan (karena angkat).
Misalnya, ekspresi fungsi:
// TypeError: functionOne is not a function
functionOne();
var functionOne = function() {
console.log("Hello!");
};
Dan, deklarasi fungsi:
// Outputs: "Hello!"
functionTwo();
function functionTwo() {
console.log("Hello!");
}
Ini juga berarti anda dapat't kondisional mendefinisikan fungsi-fungsi yang menggunakan deklarasi fungsi:
if (test) {
// Error or misbehavior
function functionThree() { doSomething(); }
}
Di atas benar-benar mendefinisikan functionThree
terlepas dari test
's nilai — kecuali menggunakan ketat
dalam efek, dalam hal ini hanya menimbulkan kesalahan.
Pertama saya ingin benar Greg: function abc(){}
scoped terlalu — nama abc
didefinisikan dalam ruang lingkup di mana definisi ini ditemui. Contoh:
function xyz(){
function abc(){};
// abc is defined here...
}
// ...but not here
Kedua, adalah mungkin untuk menggabungkan kedua gaya:
var xyz = function abc(){};
xyz
akan diartikan seperti biasa, abc
yang tidak terdefinisi di semua browser, tapi Internet Explorer — tidak bergantung pada hal yang didefinisikan. Tapi itu akan ditentukan dalam tubuh:
var xyz = function abc(){
// xyz is visible here
// abc is visible here
}
// xyz is visible here
// abc is undefined here
Jika anda ingin alias fungsi pada semua browser, menggunakan jenis deklarasi:
function abc(){};
var xyz = abc;
Dalam hal ini, kedua xyz
dan abc
adalah alias dari objek yang sama:
console.log(xyz === abc); // prints "true"
Salah satu alasan kuat untuk menggunakan gabungan gaya adalah "" atribut fungsi objek (tidak didukung oleh Internet Explorer). Pada dasarnya ketika anda mendefinisikan fungsi seperti
function abc(){};
console.log(abc.name); // prints "abc"
namanya sudah ditetapkan secara otomatis. Tapi ketika anda menentukan seperti
var abc = function(){};
console.log(abc.name); // prints ""
namanya adalah kosong — kami menciptakan fungsi anonim dan ditugaskan untuk beberapa variabel.
Alasan lain yang baik untuk menggunakan gabungan gaya adalah dengan menggunakan short internal nama untuk merujuk pada dirinya sendiri, sambil memberikan panjang non-bentrok nama untuk pengguna eksternal:
// Assume really.long.external.scoped is {}
really.long.external.scoped.name = function shortcut(n){
// Let it call itself recursively:
shortcut(n - 1);
// ...
// Let it pass itself as a callback:
someFunction(shortcut);
// ...
}
Dalam contoh di atas kita dapat melakukan hal yang sama dengan nama eksternal, tapi itu'll terlalu berat (dan lambat).
(Cara lain untuk merujuk pada dirinya sendiri adalah dengan menggunakan argumen.callee
, yang masih relatif lama, dan tidak didukung dalam modus yang ketat.)
Deep down, JavaScript memperlakukan kedua pernyataan berbeda. Ini adalah deklarasi fungsi:
function abc(){}
abc
di sini didefinisikan di mana-mana pada saat ini ruang lingkup:
// We can call it here
abc(); // Works
// Yet, it is defined down there.
function abc(){}
// We can call it again
abc(); // Works
Juga, itu dikibarkan melalui kembali
pernyataan:
// We can call it here
abc(); // Works
return;
function abc(){}
Ini adalah ekspresi fungsi:
var xyz = function(){};
xyz
di sini didefinisikan dari sudut tugas:
// We can't call it here
xyz(); // UNDEFINED!!!
// Now it is defined
xyz = function(){}
// We can call it here
xyz(); // works
Deklarasi fungsi vs. fungsi ekspresi adalah alasan sebenarnya mengapa ada perbedaan yang ditunjukkan oleh Greg.
Fakta menyenangkan:
var xyz = function abc(){};
console.log(xyz.name); // Prints "abc"
Secara pribadi, saya lebih suka "fungsi ekspresi" deklarasi karena dengan cara ini aku dapat mengontrol visibilitas. Ketika saya mendefinisikan fungsi seperti
var abc = function(){};
Saya tahu bahwa saya mendefinisikan fungsi lokal. Ketika saya mendefinisikan fungsi seperti
abc = function(){};
Aku tahu bahwa aku didefinisikan secara global menyediakan bahwa saya tidak't mendefinisikan abc
di mana saja dalam rantai lingkup. Gaya ini dari definisi yang lebih tangguh bahkan ketika digunakan di dalam eval()
. Sedangkan definisi
function abc(){};
tergantung pada konteks dan mungkin meninggalkan anda menebak di mana itu benar-benar ditentukan, terutama dalam kasus eval()
— jawabannya adalah: Itu tergantung pada browser.
Berikut ini's kumuh pada bentuk-bentuk standar yang membuat fungsi-fungsi: (Awalnya ditulis untuk pertanyaan lain, tapi disesuaikan setelah dipindahkan ke kanonik pertanyaan.) Syarat:
fungsi
Ekspresi (yang meskipun istilah, kadang-kadang membuat fungsi dengan nama-nama) fungsi
Ekspresi kelas
(ES2015+) Bentuk pertama adalah deklarasi fungsi, yang terlihat seperti ini:
function x() {
console.log('x');
}
Deklarasi fungsi adalah a deklarasi; it's bukan pernyataan atau ekspresi. Dengan demikian, anda don't mengikutinya dengan ;
(meskipun demikian ini tidak berbahaya).
Deklarasi fungsi diproses ketika eksekusi memasuki konteks di mana ia muncul, sebelum setiap langkah-demi-langkah kode dieksekusi. Fungsi ini menciptakan diberikan nama yang tepat (x
pada contoh di atas), dan nama itu dimasukkan ke dalam ruang lingkup di mana deklarasi muncul.
Karena itu's diproses sebelum ada langkah-demi-langkah kode dalam konteks yang sama, anda dapat melakukan hal-hal seperti ini:
x(); // Works even though it's above the declaration
function x() {
console.log('x');
}
Sampai ES2015, spec didn't menutupi apa mesin JavaScript yang harus dilakukan jika anda menempatkan deklarasi fungsi di dalam struktur kontrol seperti coba
, jika
, switch
, sementara
, dll., seperti ini:
if (someCondition) {
function foo() { // <===== HERE THERE
} // <===== BE DRAGONS
}
Dan sejak mereka're diproses sebelum langkah-demi-langkah kode dijalankan, it's sulit untuk tahu apa yang harus dilakukan ketika mereka're dalam sebuah struktur kontrol. Meskipun melakukan ini itu't ditentukan sampai ES2015, itu adalah diijinkan ekstensi untuk mendukung deklarasi fungsi di blok. Sayangnya (dan pasti), mesin yang berbeda melakukan hal yang berbeda. Sebagai ES2015, spesifikasi mengatakan apa yang harus dilakukan. Pada kenyataannya, memberikan tiga hal yang harus dilakukan:
"use strict";
if (someCondition) {
foo(); // Works just fine
function foo() {
}
}
console.log(typeof foo); // "undefined" (`foo` is not in scope here
// because it's not in the same block)
fungsi
EkspresiKedua bentuk umum disebut anonim fungsi ekspresi:
var y = function () {
console.log('y');
};
Seperti semua ekspresi, it's dievaluasi ketika itu's dicapai dalam langkah-demi-langkah eksekusi kode.
Di ES5, fungsi ini menciptakan tidak memiliki nama (it's anonim). Di ES2015, fungsi ini diberi nama jika mungkin dengan menyimpulkan itu dari konteks. Dalam contoh di atas, nama yang akan menjadi y
. Hal serupa dilakukan ketika fungsi adalah nilai dari properti initializer. (Untuk rincian pada ketika ini terjadi dan aturan, pencarian untuk SetFunctionName
di spesifikasi — itu muncul seluruh tempat.)
fungsi
EkspresiBentuk ketiga adalah nama fungsi ekspresi ("NFE"):
var z = function w() {
console.log('zw')
};
Fungsi ini menciptakan memiliki nama yang tepat (w
dalam kasus ini). Seperti semua ekspresi ini dievaluasi ketika itu's dicapai dalam langkah-demi-langkah eksekusi kode. Nama fungsi adalah tidak ditambahkan dengan ruang lingkup di mana ekspresi muncul; nama ** dalam lingkup di dalam fungsi itu sendiri:
var z = function w() {
console.log(typeof w); // "function"
};
console.log(typeof w); // "undefined"
Perhatikan bahwa NFEs telah sering menjadi sumber bug JavaScript untuk implementasi. IE8 dan sebelumnya, misalnya, menangani NFEs benar-benar, menciptakan dua fungsi yang berbeda pada dua waktu yang berbeda. Versi awal dari Safari memiliki masalah juga. Kabar baiknya adalah bahwa versi terbaru dari browser (IE9 dan, saat ini Safari) don't memiliki masalah lagi. (Tapi seperti tulisan ini, sayangnya, IE8 tetap digunakan secara luas, dan menggunakan NFEs dengan kode untuk web secara umum masih bermasalah.)
Kadang-kadang fungsi yang dapat menyelinap di sebagian besar tidak diketahui; yang's halnya dengan accessor fungsi. Berikut ini's contoh:
var obj = {
value: 0,
get f() {
return this.value;
},
set f(v) {
this.value = v;
}
};
console.log(obj.f); // 0
console.log(typeof obj.f); // "number"
Perhatikan bahwa ketika saya menggunakan fungsi, saya didn't menggunakan ()
! Yang's karena itu's accessor fungsi untuk properti. Kita mendapatkan dan mengatur properti dengan cara normal, tapi di belakang layar, fungsi ini dipanggil.
Anda juga dapat membuat pengakses fungsi dengan Objek.defineProperty
, Objek.defineProperties
, dan kurang dikenal argumen kedua untuk Objek.buat
.
ES2015 membawa kita panah fungsi. Berikut ini's salah satu contoh:
var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6
Melihat bahwa n => n * 2
hal yang bersembunyi di peta()
call? Yang's sebuah fungsi.
Beberapa hal tentang panah fungsi:
ini
. Sebaliknya, mereka dekat atas ini
dari konteks di mana mereka're didefinisikan. (Mereka juga menutup lebih dari argumen
dan, jika relevan, super
.) Ini berarti bahwa ini
dalam diri mereka, sama seperti ini
di mana mereka're diciptakan, dan tidak dapat diubah. fungsi
; sebaliknya, anda menggunakan =>
.
The n => n * 2
contoh di atas adalah salah satu bentuk dari mereka. Jika anda memiliki beberapa argumen untuk fungsi, anda menggunakan parens: var a = [1, 2, 3];
var b = a.map((n, i) => n * i);
console.log(b.join(", ")); // 0, 2, 6
(Ingat bahwa Array#peta
lolos masuk sebagai argumen pertama, dan indeks kedua.)
Dalam kedua kasus, tubuh fungsi adalah hanya sebuah ekspresi; fungsi's mengembalikan nilai secara otomatis akan menjadi hasil dari ekspresi itu (anda don't menggunakan eksplisit kembali
).
Jika anda're melakukan lebih dari hanya satu ekspresi, menggunakan {}
dan eksplisit return
(jika anda perlu untuk mengembalikan nilai), seperti biasa:
var a = [
{first: "Joe", last: "Bloggs"},
{first: "Albert", last: "Bloggs"},
{first: "Mary", last: "Albright"}
];
a = a.sort((a, b) => {
var rv = a.last.localeCompare(b.last);
if (rv === 0) {
rv = a.first.localeCompare(b.first);
}
return rv;
});
console.log(JSON.stringify(a));
Versi tanpa { ... }
disebut panah fungsi dengan ekspresi tubuh atau ringkas tubuh. (Juga: ringkas panah fungsi.) Satu dengan { ... }
mendefinisikan tubuh panah fungsi fungsi tubuh. (Juga: verbose panah fungsi.)
ES2015 memungkinkan bentuk pendek mendeklarasikan properti yang referensi sebuah fungsi disebut metode definisi; terlihat seperti ini:
var o = {
foo() {
}
};
hampir setara di ES5 dan sebelumnya akan sama:
var o = {
foo: function foo() {
}
};
perbedaan (lain daripada bertele-tele) adalah bahwa metode ini dapat menggunakan super
, tapi fungsi tidak. Jadi misalnya, jika anda memiliki sebuah objek yang didefinisikan (mengatakan) valueOf
menggunakan metode sintaks, bisa menggunakan super.valueOf()
untuk mendapatkan nilai Objek.prototipe.valueOf
akan kembali (sebelum mungkin melakukan sesuatu yang lain dengan itu), sedangkan ES5 versi akan memiliki untuk melakukan Objek.prototipe.valueOf.call(ini)
sebagai gantinya.
Itu juga berarti bahwa metode ini memiliki referensi ke objek itu ditentukan, jadi jika objek yang bersifat sementara (misalnya, anda're lewat itu menjadi Objek.menetapkan
sebagai salah satu sumber benda), metode sintaks bisa berarti bahwa objek yang disimpan dalam memori ketika jika tidak maka bisa saja sampah yang dikumpulkan (jika mesin JavaScript doesn't mendeteksi situasi itu dan menanganinya jika tidak ada metode menggunakan super
).
kelas
(ES2015+)ES2015 membawa kita kelas
sintaks, termasuk mendeklarasikan konstruktor dan metode:
class Person {
constructor(firstName, lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
getFullName() {
return this.firstName + " " + this.lastName;
}
}
Ada dua deklarasi fungsi di atas: Satu lagi untuk konstruktor, yang mendapat nama Orang
, dan satu untuk getFullName
, yang merupakan sebuah fungsi yang ditetapkan ke Orang.prototipe
.
Berbicara tentang konteks global, kedua, var
pernyataan dan FunctionDeclaration
pada akhirnya akan membuat non-deleteable properti global objek, tetapi nilai baik dapat ditimpa.
Perbedaan halus antara dua cara ini adalah bahwa ketika Instansiasi Variabel proses berjalan (sebelum kode aktual eksekusi) semua pengidentifikasi dinyatakan dengan var
akan diinisialisasi dengan undefined
, dan orang-orang yang digunakan oleh FunctionDeclaration
's akan tersedia sejak saat itu, misalnya:
alert(typeof foo); // 'function', it's already available
alert(typeof bar); // 'undefined'
function foo () {}
var bar = function () {};
alert(typeof bar); // 'function'
Penugasan bar
FunctionExpression
berlangsung sampai saat runtime.
Global properti yang dibuat oleh FunctionDeclaration
dapat ditimpa tanpa masalah seperti nilai variabel, misalnya:
function test () {}
test = null;
Satu lagi perbedaan yang jelas antara dua contoh di atas, adalah fungsi pertama yang doesn't memiliki nama, tapi yang kedua itu, yang dapat benar-benar berguna ketika debugging (yaitu memeriksa panggilan stack).
Tentang diedit contoh pertama (foo = function() { alert('hello!'); };
), hal ini dideklarasikan tugas, saya akan sangat mendorong anda untuk selalu menggunakan var
kata kunci.
Dengan tugas, tanpa var
pernyataan, jika dirujuk identifier tidak ditemukan dalam lingkup rantai, itu akan menjadi deleteable properti dari objek global.
Juga, dideklarasikan tugas melempar ReferenceError
pada ECMAScript 5 di bawah Strict Mode.
Harus baca:
Catatan: jawaban Ini telah digabung dari pertanyaan lain, di mana utama keraguan dan kesalahpahaman dari OP adalah pengidentifikasi yang dinyatakan dengan FunctionDeclaration
, tidak't ditimpa yang tidak terjadi.
Dua potongan kode anda've diposting di sana akan, untuk hampir semua keperluan, berperilaku dengan cara yang sama.
Namun, perbedaan dalam perilaku adalah bahwa dengan varian pertama (var functionOne = function() {}
), bahwa fungsi hanya dapat disebut setelah titik itu di dalam kode.
Dengan varian kedua (fungsi fungsi()
), fungsi ini tersedia untuk kode yang berjalan di atas dimana fungsi ini dideklarasikan.
Hal ini karena dengan varian pertama, fungsi ditugaskan untuk variabel foo
pada waktu berjalan. Kedua, fungsi yang ditugaskan untuk identifier, foo
, di parse waktu.
Informasi lebih teknis
JavaScript memiliki tiga cara mendefinisikan fungsi.
eval()
, yang memiliki masalah.Penjelasan yang lebih baik untuk Greg's jawaban
functionTwo();
function functionTwo() {
}
Mengapa tidak ada kesalahan? Kami selalu diajarkan bahwa ekspresi yang dieksekusi dari atas ke bawah(??)
deklarasi Fungsi dan deklarasi variabel adalah selalu bergerak (
mengangkat
) tak terlihat ke atas mereka mengandung lingkup oleh JavaScript penerjemah. Fungsi parameter dan bahasa-nama-nama yang ditetapkan adalah, jelas, sudah ada. ben cherry
Ini berarti bahwa kode seperti ini:
functionOne(); --------------- var functionOne;
| is actually | functionOne();
var functionOne = function(){ | interpreted |-->
}; | like | functionOne = function(){
--------------- };
Perhatikan bahwa tugas bagian deklarasi tidak mengangkat. Hanya nama ini yang mengangkat.
Tapi dalam kasus dengan deklarasi fungsi, seluruh fungsi tubuh akan mengangkat juga:
functionTwo(); --------------- function functionTwo() {
| is actually | };
function functionTwo() { | interpreted |-->
} | like | functionTwo();
---------------
Komentator lain telah menutupi perbedaan semantik dari dua varian di atas. Saya ingin untuk dicatat perbedaan gaya: Hanya "tugas" variasi dapat mengatur properti dari objek lain.
Saya sering membangun modul JavaScript dengan pola seperti ini:
(function(){
var exports = {};
function privateUtil() {
...
}
exports.publicUtil = function() {
...
};
return exports;
})();
Dengan pola ini, anda fungsi-fungsi publik akan menggunakan semua tugas, sementara pribadi anda menggunakan fungsi deklarasi.
(Perhatikan juga bahwa tugas harus membutuhkan tanda titik koma setelah pernyataan itu, sementara deklarasi melarang hal itu.)
Ilustrasi ketika harus memilih metode yang pertama ke yang kedua adalah ketika anda perlu untuk menghindari meng-override fungsi's definisi sebelumnya.
Dengan
if (condition){
function myfunction(){
// Some code
}
}
ini definisi dari myfunction
akan menimpa definisi sebelumnya, karena itu akan dilakukan di parse-waktu.
Sementara
if (condition){
var myfunction = function (){
// Some code
}
}
apakah benar pekerjaan mendefinisikan myfunction
hanya jika syarat
terpenuhi.
Alasan penting adalah untuk menambahkan satu dan hanya satu variabel sebagai "Root" anda namespace...
var MyNamespace = {}
MyNamespace.foo= function() {
}
atau
var MyNamespace = {
foo: function() {
},
...
}
Ada banyak teknik untuk namespacing. It's menjadi lebih penting dengan kebanyakan JavaScript modul yang tersedia.
Lihat juga Bagaimana cara mendeklarasikan namespace di JavaScript?
Angkat adalah kode JavaScript penerjemah adalah tindakan memindahkan semua variabel dan deklarasi fungsi ke atas lingkup saat ini.
Namun, hanya yang sebenarnya deklarasi yang mengangkat. dengan meninggalkan tugas-tugas mereka.
Javascript disebut longgar diketik bahasa. Yang berarti Javascript variabel yang dapat menyimpan nilai dari setiap [- Tipe Data][3]. Javascript secara otomatis mengurus mengubah variabel-tipe berdasarkan nilai/literal yang diberikan selama runtime.
global_Page = 10; var global_Page; « undefined
« Integer literal, Number Type. ------------------- global_Page = 10; « Number
global_Page = 'Yash'; | Interpreted | global_Page = 'Yash'; « String
« String literal, String Type. « AS « global_Page = true; « Boolean
var global_Page = true; | | global_Page = function (){ « function
« Boolean Type ------------------- var local_functionblock; « undefined
global_Page = function (){ local_functionblock = 777;« Number
var local_functionblock = 777; };
// Assigning function as a data.
};
Fungsi
function Identifier_opt ( FormalParameterList_opt ) {
FunctionBody | sequence of statements
« return; Default undefined
« return 'some data';
}
Lingkup sehubungan dengan fungsi-blok global. Lingkup sehubungan dengan halaman yang tidak terdefinisi | tidak tersedia.
Deklarasi Fungsi
function globalAccess() { function globalAccess() {
} ------------------- }
globalAccess(); | | function globalAccess() { « Re-Defined / overridden.
localAccess(); « Hoisted As « function localAccess() {
function globalAccess() { | | }
localAccess(); ------------------- localAccess(); « function accessed with in globalAccess() only.
function localAccess() { }
} globalAccess();
} localAccess(); « ReferenceError as the function is not defined
*FungsiEkspresi*
10; « literal
(10); « Expression (10).toString() -> '10'
var a;
a = 10; « Expression var a.toString() -> '10'
(function invoke() { « Expression Function
console.log('Self Invoking'); (function () {
}); }) () -> 'Self Invoking'
var f;
f = function (){ « Expression var Function
console.log('var Function'); f () -> 'var Function'
};
Fungsi yang ditetapkan ke variabel Contoh:
(function selfExecuting(){
console.log('IIFE - Immediately-Invoked Function Expression');
}());
var anonymous = function (){
console.log('anonymous function Expression');
};
var namedExpression = function for_InternalUSE(fact){
if(fact === 1){
return 1;
}
var localExpression = function(){
console.log('Local to the parent Function Scope');
};
globalExpression = function(){
console.log('creates a new global variable, then assigned this function.');
};
//return; //undefined.
return fact * for_InternalUSE( fact - 1);
};
namedExpression();
globalExpression();
javascript diartikan sebagai
var anonymous;
var namedExpression;
var globalExpression;
anonymous = function (){
console.log('anonymous function Expression');
};
namedExpression = function for_InternalUSE(fact){
var localExpression;
if(fact === 1){
return 1;
}
localExpression = function(){
console.log('Local to the parent Function Scope');
};
globalExpression = function(){
console.log('creates a new global variable, then assigned this function.');
};
return fact * for_InternalUSE( fact - 1); // DEFAULT UNDEFINED.
};
namedExpression(10);
globalExpression();
Anda dapat memeriksa deklarasi fungsi, ekspresi test dari browser yang berbeda's menggunakan jsperf Test Runner
ES5 Fungsi Constructor Kelas: Fungsi benda-benda yang dibuat dengan menggunakan Fungsi.prototipe.mengikat
JavaScript memperlakukan fungsi sebagai kelas objek, sehingga menjadi sebuah objek, anda dapat menetapkan sifat-sifat fungsi.
function Shape(id) { // Function Declaration
this.id = id;
};
// Adding a prototyped method to a function.
Shape.prototype.getID = function () {
return this.id;
};
Shape.prototype.setID = function ( id ) {
this.id = id;
};
var expFn = Shape; // Function Expression
var funObj = new Shape( ); // Function Object
funObj.hasOwnProperty('prototype'); // false
funObj.setID( 10 );
console.log( funObj.getID() ); // 10
ES6 diperkenalkan Panah fungsi: panah fungsi ekspresi yang lebih singkat, sintaks, mereka yang paling cocok untuk non-metode fungsi, dan mereka tidak dapat digunakan sebagai konstruktor.
ArrowFunction : ArrowParameters => ConciseBody
.const fn = (item) => { mengembalikan item & 1 ? 'Aneh' : 'Bahkan'; }; konsol.log( fn(2) ); // Bahkan konsol.log( fn(3) ); // Ganjil
[3]: https://msdn.microsoft.com/en-us/library/7wkd9z69(v=vs. 94).aspx
I'm menambahkan saya sendiri jawabannya hanya karena orang lain telah menutupi mengangkat bagian secara menyeluruh.
I've bertanya-tanya tentang cara yang lebih baik untuk waktu yang lama sekarang, dan terima kasih untuk http://jsperf.com sekarang aku tahu :)
Deklarasi fungsi yang lebih cepat, dan yang's apa yang benar-benar penting di web dev kan? ;)
Deklarasi fungsi dan fungsi ekspresi yang ditugaskan untuk variabel berperilaku sama sekali pengikatan ini ditetapkan.
Ada perbedaan namun pada cara dan ketika fungsi objek adalah benar-benar berhubungan dengan variabel. Perbedaan ini disebabkan mekanisme yang disebut variabel angkat dalam JavaScript.
Pada dasarnya, semua fungsi deklarasi dan deklarasi variabel adalah mengangkat ke atas fungsi di mana deklarasi terjadi (ini adalah mengapa kita mengatakan bahwa JavaScript fungsi ruang lingkup).
Ketika deklarasi fungsi adalah mengangkat, fungsi tubuh "berikut" jadi ketika fungsi tubuh dievaluasi, variabel akan segera terikat untuk fungsi objek.
Ketika deklarasi variabel adalah mengangkat, inisialisasi tidak tidak
ikuti, tetapi "tertinggal". Variabel diinisialisasi ke
undefined
di mulai dari fungsi tubuh, dan akan yang ditugaskan
nilai pada lokasi semula dalam kode. (Sebenarnya, itu akan diberi nilai setiap lokasi di mana deklarasi variabel dengan nama yang sama terjadi.)
Urutan mengangkat ini juga penting: deklarasi fungsi didahulukan dari deklarasi variabel dengan nama yang sama, dan terakhir deklarasi fungsi lebih diutamakan daripada sebelumnya deklarasi fungsi dengan nama yang sama.
Beberapa contoh...
var foo = 1;
function bar() {
if (!foo) {
var foo = 10 }
return foo; }
bar() // 10
Variabel foo
adalah mengangkat ke atas fungsi, diinisialisasi untuk undefined
, sehingga !foo
adalah benar
, sehingga foo
ditugaskan 10
. The foo
luar bar
's lingkup tidak memainkan peranan dan tak tersentuh.
function f() {
return a;
function a() {return 1};
var a = 4;
function a() {return 2}}
f()() // 2
function f() {
return a;
var a = 4;
function a() {return 1};
function a() {return 2}}
f()() // 2
Deklarasi fungsi didahulukan dari deklarasi variabel, dan terakhir deklarasi fungsi "tongkat".
function f() {
var a = 4;
function a() {return 1};
function a() {return 2};
return a; }
f() // 4
Dalam contoh ini a
diinisialisasi dengan fungsi objek yang dihasilkan dari evaluasi kedua deklarasi fungsi, dan kemudian ditugaskan 4
.
var a = 1;
function b() {
a = 10;
return;
function a() {}}
b();
a // 1
Berikut deklarasi fungsi adalah dikibarkan pertama, mendeklarasikan dan menginisialisasi variabel a
. Selanjutnya, variabel ini ditetapkan 10
. Dengan kata lain: tugas tidak menetapkan ke luar variabel a
.
Contoh pertama adalah deklarasi fungsi:
function abc(){}
Contoh kedua adalah fungsi ekspresi:
var abc = function() {};
Perbedaan utama adalah bagaimana mereka mengangkat (dicabut dan dinyatakan). Pada contoh pertama, seluruh deklarasi fungsi mengangkat. Pada contoh kedua hanya var 'abc' mengangkat, nilai (fungsi) akan menjadi tidak terdefinisi, dan fungsi itu sendiri tetap pada posisi yang dinyatakan.
Sederhananya:
//this will work
abc(param);
function abc(){}
//this would fail
abc(param);
var abc = function() {}
Untuk mempelajari lebih lanjut tentang topik ini, saya sangat menyarankan anda ini link
Dalam hal kode biaya pemeliharaan, bernama fungsi yang lebih disukai:
Terlepas dari tempat di mana mereka menyatakan (tetapi masih terbatas oleh ruang lingkup).
Saya menduga lebih lanjut untuk nama fungsi yang diikuti. Dan apa yang tercantum sebagai keuntungan bernama fungsi kerugian untuk anonim yang.
Secara historis, fungsi anonim yang muncul dari ketidakmampuan JavaScript sebagai bahasa untuk daftar anggota dengan nama fungsi:
{
member:function() { /* How do I make "this.member" a named function? */
}
}
Saya menggunakan variabel pendekatan dalam kode saya untuk alasan yang sangat spesifik, teori yang telah dibahas dalam abstrak cara di atas, tapi sebuah contoh mungkin bisa membantu beberapa orang seperti saya, dengan keterbatasan keahlian JavaScript.
Saya memiliki kode yang saya butuhkan untuk menjalankan dengan 160 independen yang dirancang brandings. Sebagian besar kode ini di file bersama, tapi branding-hal spesifik dalam file yang terpisah, satu untuk masing-masing merek.
Beberapa brandings memerlukan fungsi-fungsi tertentu, dan beberapa tidak. Kadang-kadang saya harus menambahkan fungsi baru untuk melakukan branding baru-hal-hal tertentu. Saya senang untuk mengubah ruang kode, tapi aku don't ingin mengubah semua 160 set branding file.
Dengan menggunakan variabel sintaks, saya dapat mendeklarasikan variabel (fungsi pointer pada dasarnya) di ruang kode dan menetapkan sepele rintisan fungsi, atau set ke null.
Satu atau dua brandings yang perlu spesifik pelaksanaan fungsi kemudian dapat menentukan versi dari fungsi dan menetapkan ini untuk variabel jika mereka ingin, dan sisanya melakukan apa-apa. Aku dapat menguji fungsi nol sebelum saya jalankan di kode bersama.
Dari orang-orang's komentar di atas, saya menyimpulkan ini mungkin menjadi mungkin untuk mendefinisikan fungsi statis juga, tapi saya pikir variabel solusi yang lebih bagus dan jelas.
Dalam ilmu komputer, istilah, kita berbicara tentang fungsi anonim dan nama fungsi. Saya pikir perbedaan yang paling penting adalah bahwa fungsi anonim tidak terikat untuk sebuah nama, maka nama fungsi anonim. Di JavaScript itu adalah kelas objek dinyatakan secara dinamis pada saat runtime.
Untuk informasi lebih lanjut tentang fungsi anonim dan kalkulus lambda, Wikipedia adalah awal yang baik (http://en.wikipedia.org/wiki/Anonymous_function).
Greg's Jawaban adalah cukup baik, tapi aku masih ingin menambahkan sesuatu untuk itu yang saya pelajari sekarang menonton Douglas Crockford's video.
Ekspresi fungsi:
var foo = function foo() {};
Fungsi pernyataan:
function foo() {};
Fungsi pernyataan adalah singkatan untuk var
pernyataan dengan fungsi
nilai.
Jadi
function foo() {};
mengembang untuk
var foo = function foo() {};
Yang memperluas lebih lanjut ke:
var foo = undefined;
foo = function foo() {};
Dan mereka berdua mengangkat ke atas kode.
@EugeneLazutkin memberikan contoh di mana ia nama-nama yang ditugaskan fungsi untuk dapat menggunakan jalan pintas()
sebagai referensi internal untuk dirinya sendiri. John Resig memberikan contoh lain - menyalin fungsi rekursif ditugaskan ke objek lain dalam Lanjutan Belajar Javascript tutorial. Sementara menetapkan fungsi ke sifat isn't ketat pertanyaan di sini, saya sarankan secara aktif mencoba tutorial keluar - menjalankan kode dengan mengklik tombol di sudut kanan atas, dan klik dua kali kode untuk mengedit sesuai dengan keinginan anda.
Contoh-contoh dari tutorial: pemanggilan rekursif dalam berteriak()
:
Tes gagal ketika original ninja objek dihapus. (halaman 13)
var ninja = {
yell: function(n){
return n > 0 ? ninja.yell(n-1) + "a" : "hiy";
}
};
assert( ninja.yell(4) == "hiyaaaa", "A single object isn't too bad, either." );
var samurai = { yell: ninja.yell };
var ninja = null;
try {
samurai.yell(4);
} catch(e){
assert( false, "Uh, this isn't good! Where'd ninja.yell go?" );
}
Jika anda nama fungsi yang akan dipanggil secara rekursif, tes akan lulus. (halaman 14)
var ninja = {
yell: function yell(n){
return n > 0 ? yell(n-1) + "a" : "hiy";
}
};
assert( ninja.yell(4) == "hiyaaaa", "Works as we would expect it to!" );
var samurai = { yell: ninja.yell };
var ninja = {};
assert( samurai.yell(4) == "hiyaaaa", "The method correctly calls itself." );
Perbedaan lain yang tidak disebutkan dalam jawaban yang lain adalah bahwa jika anda menggunakan fungsi anonim
var functionOne = function() {
// Some code
};
dan gunakan itu sebagai konstruktor seperti di
var one = new functionOne();
kemudian satu.konstruktor.nama
tidak akan ditetapkan. Fungsi.nama
non-standar, tetapi didukung oleh Firefox, Chrome, dan lainnya Webkit-berasal browser dan IE 9+.
Dengan
function functionTwo() {
// Some code
}
two = new functionTwo();
hal ini dimungkinkan untuk mengambil nama dari constructor string dengan dua.konstruktor.nama
.
Yang pertama (fungsi melakukan sesuatu(x)) harus menjadi bagian dari sebuah object notation.
Yang kedua (var melakukan sesuatu = function(x){ alert(x);}
) hanya menciptakan fungsi anonim dan menetapkan variabel, melakukan sesuatu
. Jadi melakukan sesuatu() akan memanggil fungsi.
Anda mungkin ingin tahu apa deklarasi fungsi dan fungsi ekspresi adalah.
Deklarasi fungsi mendefinisikan nama fungsi variabel tanpa memerlukan variabel tugas. Deklarasi fungsi terjadi sebagai standalone konstruksi dan tidak dapat bersarang di dalam non-blok fungsi.
function foo() {
return 3;
}
ECMA 5 (13.0) mendefinisikan sintaks sebagai
function Identifier ( FormalParameterListpilih ) { FunctionBody }
Dalam kondisi di atas nama fungsi ini terlihat dalam ruang lingkup dan cakupan induknya (jika tidak maka akan tidak terjangkau).
Dan dalam fungsi ekspresi
Fungsi ekspresi mendefinisikan fungsi sebagai bagian dari yang lebih besar sintaks ekspresi (biasanya variabel tugas ). Fungsi yang didefinisikan melalui fungsi ekspresi dapat diberi nama atau anonim. Fungsi ekspresi tidak harus mulai dengan "fungsi".
// Anonymous function expression
var a = function() {
return 3;
}
// Named function expression
var a = function foo() {
return 3;
}
// Self-invoking function expression
(function foo() {
alert("hello!");
})();
ECMA 5 (13.0) mendefinisikan sintaks sebagai
fungsi Pengenalpilih ( FormalParameterListpilih ) { FunctionBody }