var functionName = function () {} vs function functionName () {}

6876

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?

Richard Garside
sumber
198
permadi.com/tutorial/jsFunc/index.html adalah halaman yang sangat bagus tentang fungsi javascript
uzay95
67
Terkait adalah artikel yang sangat baik ini tentang Ekspresi Fungsi Bernama .
Phrogz
12
@CMS mereferensikan artikel ini: kangax.github.com/nfe/#expr-vs-decl
Upperstage
106
Ada dua hal yang perlu Anda waspadai: # 1 Dalam JavaScript, deklarasi diangkat. Artinya var a = 1; var b = 2;menjadi var 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.
xavierm02
65
Oh dan btw, sintaks yang benar adalah dengan ";" setelah penugasan dan tanpa setelah deklarasi. Misalnya function f(){}vs var f = function(){};.
xavierm02

Jawaban:

5045

Perbedaannya adalah bahwa itu functionOneadalah ekspresi fungsi dan hanya ditentukan ketika garis itu tercapai, sedangkan functionTwoadalah deklarasi fungsi dan didefinisikan segera setelah fungsi atau skrip sekitarnya dijalankan (karena mengangkat ).

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!");
}

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.

'use strict';    
{ // note this block!
  function functionThree() {
    console.log("Hello!");
  }
}
functionThree(); // ReferenceError

Greg
sumber
632
@Reg: Omong-omong, perbedaannya bukan hanya mereka diurai pada waktu yang berbeda. Pada dasarnya, Anda functionOnehanyalah sebuah variabel yang memiliki fungsi anonim yang ditugaskan untuknya, sedangkan functionTwosebenarnya adalah fungsi bernama. Panggil .toString()keduanya untuk melihat perbedaannya. Ini penting dalam beberapa kasus di mana Anda ingin mendapatkan nama fungsi secara terprogram.
Jason Bunting
6
@Jason Bunting .. tidak yakin apa yang Anda dapatkan di sini, .toString () tampaknya mengembalikan nilai yang pada dasarnya sama (definisi fungsi) untuk keduanya: cl.ly/2a2C2Y1r0J451o0q0B1B
Jon z
124
Ada keduanya berbeda. Yang pertama adalah function expressionyang kedua adalah function declaration. Anda dapat membaca lebih lanjut tentang topik ini di sini: javascriptweblog.wordpress.com/2010/07/06/…
Michal Kuklis
127
@Reg Bagian dari jawaban Anda mengenai waktu parse vs waktu berjalan tidak benar. Dalam JavaScript, deklarasi fungsi tidak didefinisikan selama waktu parse, tetapi selama waktu berjalan. Prosesnya seperti ini: Kode sumber diurai -> program JavaScript dievaluasi -> Konteks eksekusi global diinisialisasi -> instantiasi pengikatan pernyataan dilakukan. Selama proses ini, deklarasi fungsi adalah instantiated (lihat langkah 5 Bab 10.5 ).
Šime Vidas
102
Terminologi untuk fenomena ini dikenal sebagai mengangkat.
Colin Pear
1943

Pertama, saya ingin mengoreksi Greg: function abc(){}dicakup juga - namanya abcdidefinisikan dalam lingkup di mana definisi ini ditemukan. Contoh:

function xyz(){
  function abc(){};
  // abc is defined here...
}
// ...but not here

Kedua, dimungkinkan untuk menggabungkan kedua gaya:

var xyz = function abc(){};

xyzakan didefinisikan seperti biasa, abctidak terdefinisi di semua browser tetapi Internet Explorer - jangan bergantung pada itu yang didefinisikan. Tetapi itu akan didefinisikan di dalam tubuhnya:

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 di semua browser, gunakan deklarasi semacam ini:

function abc(){};
var xyz = abc;

Dalam hal ini, baik xyzdan abcadalah alias dari objek yang sama:

console.log(xyz === abc); // prints "true"

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

function abc(){};
console.log(abc.name); // prints "abc"

namanya ditetapkan secara otomatis. Tetapi ketika Anda mendefinisikannya seperti

var abc = function(){};
console.log(abc.name); // prints ""

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:

// 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);
  // ...
}

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:

function abc(){}

abc di sini didefinisikan di mana-mana dalam lingkup saat ini:

// We can call it here
abc(); // Works

// Yet, it is defined down there.
function abc(){}

// We can call it again
abc(); // Works

Juga, ia mengangkat melalui returnpernyataan:

// We can call it here
abc(); // Works
return;
function abc(){}

Ini adalah ekspresi fungsi:

var xyz = function(){};

xyz di sini didefinisikan dari sudut penugasan:

// We can't call it here
xyz(); // UNDEFINED!!!

// Now it is defined
xyz = function(){}

// We can call it here
xyz(); // works

Deklarasi fungsi vs. ekspresi fungsi 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 deklarasi "fungsi ekspresi" karena dengan cara ini saya dapat mengontrol visibilitas. Ketika saya mendefinisikan fungsi suka

var abc = function(){};

Saya tahu bahwa saya mendefinisikan fungsi secara lokal. Ketika saya mendefinisikan fungsi suka

abc = function(){};

Saya tahu bahwa saya mendefinisikannya secara global asalkan saya tidak mendefinisikan abcdi mana pun dalam rantai cakupan. Gaya definisi ini tahan walaupun digunakan di dalam eval(). Sedangkan definisinya

function abc(){};

tergantung pada konteks dan dapat membuat Anda menebak di mana sebenarnya didefinisikan, terutama dalam kasus eval()- jawabannya adalah: Tergantung pada browser.

Eugene Lazutkin
sumber
69
Saya merujuk ke RoBorg tetapi dia tidak bisa ditemukan. Sederhana: RoBorg === Greg. Begitulah sejarah dapat ditulis ulang di zaman internet. ;-)
Eugene Lazutkin
10
var xyz = function abc () {}; console.log (xyz === abc); Semua browser yang telah saya uji (Safari 4, Firefox 3.5.5, Opera 10.10) memberi saya "Undefined variable: abc".
NVI
7
Secara keseluruhan saya pikir posting ini melakukan pekerjaan yang baik untuk menjelaskan perbedaan dan keuntungan dari penggunaan deklarasi fungsi. Saya akan setuju untuk tidak setuju sejauh manfaat dari penggunaan penugasan ekspresi fungsi ke variabel terutama karena "manfaat" tampaknya merupakan advokasi untuk mendeklarasikan entitas global ... dan semua orang tahu bahwa Anda tidak boleh mengacaukan namespace global , Baik? ;-)
natlee75
83
Salah satu alasan besar untuk menggunakan fungsi bernama adalah karena debugger dapat menggunakan nama untuk membantu Anda memahami panggilan stack atau jejak stack. itu menyebalkan ketika Anda melihat tumpukan panggilan dan melihat "fungsi anonim" 10 tingkat dalam ...
kambing
3
var abc = function(){}; console.log(abc.name);tidak menghasilkan ""lagi, tetapi "abc"sebaliknya.
Qwerty
632

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" functionEkspresi (yang terlepas dari istilah tersebut, terkadang membuat fungsi dengan nama)

  • Bernama functionEkspresi

  • Penginisialisasi 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:

function x() {
    console.log('x');
}

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:

x(); // Works even though it's above the declaration
function x() {
    console.log('x');
}

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:

if (someCondition) {
    function foo() {    // <===== HERE THERE
    }                   // <===== BE DRAGONS
}

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:

  1. Jika dalam mode longgar bukan pada browser web, mesin JavaScript seharusnya melakukan satu hal
  2. Jika dalam mode longgar di browser web, mesin JavaScript seharusnya melakukan hal lain
  3. Jika dalam mode ketat (browser atau tidak), mesin JavaScript seharusnya melakukan hal lain lagi

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:

"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)

functionEkspresi "Anonim"

Bentuk umum kedua disebut ekspresi fungsi anonim :

var y = function () {
    console.log('y');
};

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, cari SetFunctionNamedalam spesifikasi  - itu muncul di semua tempat.)

functionEkspresi Bernama

Bentuk ketiga adalah ekspresi fungsi bernama ("NFE"):

var z = function w() {
    console.log('zw')
};

Fungsi yang dibuat ini memiliki nama yang tepat ( wdalam 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:

var z = function w() {
    console.log(typeof w); // "function"
};
console.log(typeof w);     // "undefined"

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:

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 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 untuk Object.create.

Ekspresi Fungsi Panah (ES2015 +)

ES2015 memberi kita fungsi panah . Ini salah satu contohnya:

var a = [1, 2, 3];
var b = a.map(n => n * 2);
console.log(b.join(", ")); // 2, 4, 6

Lihat n => n * 2benda itu bersembunyi di map()telepon? Itu sebuah fungsi.

Beberapa hal tentang fungsi panah:

  1. Mereka tidak punya sendiri this. Sebaliknya, mereka dekat selama ini thisdari konteks di mana mereka didefinisikan. (Mereka juga menutup argumentsdan, jika relevan super,.) Ini berarti bahwa di thisdalam mereka sama dengan di thismana mereka diciptakan, dan tidak dapat diubah.

  2. Seperti yang Anda perhatikan di atas, Anda tidak menggunakan kata kunci function; sebaliknya, Anda gunakan =>.

The n => n * 2contoh di atas merupakan salah satu bentuk dari mereka. Jika Anda memiliki beberapa argumen untuk melewati 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 yang Array#mapmelewati 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 eksplisit return(jika Anda perlu 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 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:

var o = {
    foo() {
    }
};

yang hampir setara di ES5 dan sebelumnya adalah:

var o = {
    foo: function foo() {
    }
};

perbedaannya (selain verbositas) adalah suatu metode dapat digunakan super, tetapi suatu fungsi tidak bisa. Jadi misalnya, jika Anda memiliki objek yang didefinisikan (katakanlah) valueOfmenggunakan sintaksis metode, itu bisa digunakan super.valueOf()untuk mendapatkan nilai Object.prototype.valueOfakan kembali (sebelum mungkin melakukan sesuatu yang lain dengan itu), sedangkan versi ES5 harus melakukan Object.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.assignsalah 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 digunakan super).

Konstruktor dan Deklarasi Metode dalam class(ES2015 +)

ES2015 membawa kita classsintaks, termasuk konstruktor dan metode yang dideklarasikan:

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    getFullName() {
        return this.firstName + " " + this.lastName;
    }
}

Ada dua deklarasi fungsi di atas: Satu untuk konstruktor, yang mendapatkan nama Person, dan satu untuk getFullName, yang merupakan fungsi yang ditugaskan untuk Person.prototype.

TJ Crowder
sumber
3
lalu nama witu diabaikan begitu saja?
BiAiB
8
@PellePenna: Nama fungsi berguna untuk banyak hal. Dua biggies dalam pandangan saya adalah rekursi, dan nama fungsi yang ditampilkan di tumpukan panggilan, jejak pengecualian, dan semacamnya.
TJ Crowder
4
@ChaimEliyah - "Menerima bukan berarti itu jawaban terbaik, itu hanya berarti itu bekerja untuk orang yang bertanya." sumber
ScrapCode
6
@ AR: Cukup benar. Namun, yang mengherankan, tepat di atas tertulis "Jawaban terbaik muncul terlebih dahulu sehingga selalu mudah ditemukan." Karena jawaban yang diterima muncul pertama kali bahkan lebih dari jawaban dengan suara lebih tinggi, tur mungkin agak bertentangan dengan diri sendiri. ;-) Juga sedikit tidak akurat, jika kita menentukan "terbaik" dengan suara (yang tidak dapat diandalkan, hanya apa yang kita punya), jawaban "terbaik" hanya muncul terlebih dahulu jika Anda menggunakan tab "Votes" - jika tidak, jawaban yang pertama adalah yang aktif, atau yang tertua.
TJ Crowder
1
@TJCrowder: Setuju. 'diatur berdasarkan tanggal' terkadang menjengkelkan.
ScrapCode
144

Berbicara tentang konteks global, keduanya, varpernyataan dan a FunctionDeclarationpada 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 varakan diinisialisasi dengan undefined, dan 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 FunctionExpressionberlangsung hingga runtime.

Properti global yang dibuat oleh a FunctionDeclarationdapat ditimpa tanpa masalah sama seperti nilai variabel, misalnya:

 function test () {}
 test = null;

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 menggunakan varkata kunci.

Dengan penugasan, tanpa varpernyataan, 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 ReferenceErrorECMAScript 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.

CMS
sumber
Saya tidak tahu bahwa fungsi dapat ditimpa dalam JavaScript! Juga, pesanan parse adalah titik penjualan besar bagi saya. Saya kira saya perlu melihat bagaimana saya membuat fungsi.
Xeoncross
2
+0 ke artikel "Nama fungsi ekspresi demistified" karena 404ing. Kemungkinan mirror ?: kangax.github.com/nfe
Mr_Chimp
@ CMS Bagus. Ingatlah bahwa saya tidak pernah melihat yang asli jadi saya tidak tahu apakah itu sebuah cermin atau hanya artikel lain dengan judul yang sama!
Mr_Chimp
@ Mr_Chimp Saya cukup yakin itu, thewaybackmachine mengatakan bahwa ia mendapat 302 pada waktu merangkak dan pengalihan ke tautan yang Anda berikan.
John
124

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 foosaat run time. Di yang kedua, fungsi ditugaskan untuk pengidentifikasi itu foo,, pada waktu parse.

Lebih banyak informasi teknis

JavaScript memiliki tiga cara untuk mendefinisikan fungsi.

  1. Cuplikan pertama Anda menunjukkan ekspresi fungsi . Ini melibatkan penggunaan operator "fungsi" untuk membuat fungsi - hasil dari operator itu dapat disimpan dalam variabel atau properti objek apa pun. Ekspresi fungsi sangat kuat seperti itu. Ekspresi fungsi sering disebut "fungsi anonim", karena tidak harus memiliki nama,
  2. Contoh kedua Anda adalah deklarasi fungsi . Ini menggunakan pernyataan "fungsi" untuk membuat fungsi. Fungsi ini tersedia pada waktu parse dan dapat dipanggil di mana saja dalam lingkup itu. Anda masih bisa menyimpannya di properti variabel atau objek nanti.
  3. Cara ketiga untuk mendefinisikan suatu fungsi adalah konstruktor "Function ()" , yang tidak ditampilkan di posting asli Anda. Tidak disarankan untuk menggunakan ini karena berfungsi dengan cara yang sama eval(), yang memiliki masalah.
thomasrutter
sumber
103

Penjelasan yang lebih baik untuk jawaban Greg

functionTwo();
function functionTwo() {
}

Kenapa tidak ada kesalahan? Kami selalu diajarkan bahwa ekspresi dieksekusi dari atas ke bawah (??)

Karena:

Deklarasi fungsi dan deklarasi variabel selalu dipindahkan ( hoisted) tanpa terlihat ke bagian atas ruang lingkupnya yang mengandung penerjemah JavaScript. Parameter fungsi dan nama yang didefinisikan bahasa sudah jelas ada. ben cherry

Ini berarti bahwa kode seperti ini:

functionOne();                  ---------------      var functionOne;
                                | is actually |      functionOne();
var functionOne = function(){   | interpreted |-->
};                              |    like     |      functionOne = function(){
                                ---------------      };

Perhatikan bahwa bagian penugasan deklarasi tidak diangkat. Hanya namanya yang diangkat.

Tetapi dalam kasus dengan deklarasi fungsi, seluruh fungsi tubuh akan diangkat juga :

functionTwo();              ---------------      function functionTwo() {
                            | is actually |      };
function functionTwo() {    | interpreted |-->
}                           |    like     |      functionTwo();
                            ---------------
suhailvs
sumber
HI suhail terima kasih atas info yang jelas tentang topik fungsi. Sekarang pertanyaan saya adalah mana yang akan menjadi deklarasi pertama dalam hirarki deklarasi apakah deklarasi variabel (functionOne) atau deklarasi fungsi (functionTwo)?
Sharathi RB
91

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:

(function(){
    var exports = {};

    function privateUtil() {
            ...
    }

    exports.publicUtil = function() {
            ...
    };

    return exports;
})();

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.)

Sean McMillan
sumber
4
yuiblog.com/blog/2007/06/12/module-pattern adalah referensi primordial untuk pola modul, sejauh yang saya tahu. (Meskipun artikel itu menggunakan var foo = function(){...}sintaks bahkan untuk variabel pribadi.
Sean McMillan
Sebenarnya ini tidak sepenuhnya benar dalam beberapa versi IE yang lebih lama. ( function window.onload() {}adalah suatu hal.)
Ry-
77

Ilustrasi kapan memilih metode pertama daripada yang kedua adalah ketika Anda harus menghindari mengesampingkan definisi fungsi sebelumnya.

Dengan

if (condition){
    function myfunction(){
        // Some code
    }
}

, definisi ini myfunctionakan menggantikan definisi sebelumnya, karena akan dilakukan pada waktu parse.

Sementara

if (condition){
    var myfunction = function (){
        // Some code
    }
}

melakukan pekerjaan yang benar untuk mendefinisikan myfunctionhanya ketika conditionbertemu.

Mbengue Assane
sumber
1
contoh ini baik dan dekat dengan kesempurnaan, tetapi dapat ditingkatkan. contoh yang lebih baik adalah mendefinisikan di 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.
Alexander Mills
62

Alasan penting adalah untuk menambahkan satu dan hanya satu variabel sebagai "Root" dari namespace Anda ...

var MyNamespace = {}
MyNamespace.foo= function() {

}

atau

var MyNamespace = {
  foo: function() {
  },
  ...
}

Ada banyak teknik untuk namespacing. Ini menjadi lebih penting dengan banyaknya modul JavaScript yang tersedia.

Lihat juga Bagaimana cara mendeklarasikan namespace dalam JavaScript?

rampok
sumber
3
Tampaknya jawaban ini digabungkan ke dalam pertanyaan ini dari pertanyaan lain, dan kata-katanya mungkin agak tidak berhubungan dengan pertanyaan ini . Apakah Anda mempertimbangkan untuk mengedit jawaban sehingga sepertinya lebih diarahkan secara khusus pada pertanyaan ini? (untuk mengulangi; ini sama sekali bukan kesalahan Anda ... hanya efek samping dari pertanyaan yang digabungkan). Anda juga dapat menghapusnya, dan saya pikir Anda akan menjaga reputasi Anda. Atau Anda bisa meninggalkannya; karena sudah tua, itu mungkin tidak membuat perbedaan besar.
Andrew Barber
55

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 / Fungsi yang dideklarasikan di dalam halaman bersifat global dapat diakses di mana saja di halaman itu.
  • variabel / Fungsi yang dideklarasikan di dalam fungsi memiliki cakupan lokal. berarti mereka tersedia / diakses di dalam badan fungsi (ruang lingkup), mereka tidak tersedia di luar badan fungsi.

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.

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';
}
  • fungsi yang dideklarasikan di dalam halaman diangkat ke atas halaman yang memiliki akses global.
  • fungsi yang dideklarasikan di dalam blok fungsi diangkat ke atas blok.
  • Nilai pengembalian default fungsi adalah ' tidak terdefinisi ', Nilai default deklarasi variabel juga 'tidak terdefinisi'

    Scope with respect to function-block global. 
    Scope with respect to page undefined | not available.

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

Ekspresi fungsi

        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 ditugaskan 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, 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.

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 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.

ArrowFunction : ArrowParameters => ConciseBody.

const fn = (item) => { return item & 1 ? 'Odd' : 'Even'; };
console.log( fn(2) ); // Even
console.log( fn(3) ); // Odd
Yash
sumber
3
ahm, jawaban Anda ... bukankah ambigu? ditulis dengan baik jadi +1 untuk menghabiskan dan menulis terlalu banyak info.
Denmark
40

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 :)

masukkan deskripsi gambar di sini

Deklarasi fungsi lebih cepat, dan itulah yang benar-benar penting di web dev, kan? ;)

Leon Gaban
sumber
8
Saya akan mengatakan bahwa perawatan adalah aspek terpenting dari sebagian besar kode. Performa itu penting, tetapi dalam banyak kasus IO cenderung menjadi penghambat yang lebih besar dari cara Anda mendefinisikan fungsi Anda. Namun ada beberapa masalah di mana Anda membutuhkan setiap bit kinerja yang bisa Anda dapatkan dan ini berguna dalam kasus tersebut. Juga bagus untuk memiliki jawaban di sini yang menjawab bagian pertanyaan dengan jelas.
Richard Garside
3
Yah, saya merasa sebaliknya dengan Firefox. jsperf.com/sandytest
Sandeep Nayak
Hanya pembaruan, karena saya sudah menggunakan gaya pemrograman fungsional penuh dalam JavaScript sekarang, saya tidak pernah menggunakan deklarasi, hanya ekspresi fungsi sehingga saya dapat menghubungkan dan memanggil fungsi saya dengan nama variabel mereka. Lihat RamdaJS ...
Leon Gaban
1
@SandeepNayak Saya baru saja menjalankan tes Anda sendiri di Firefox 50.0.0 / Windows 7 0.0.0, dan itu sebenarnya sama dengan cara Leon. Jadi jika pengujian Anda benar, saya akan menyimpulkan bahwa tes jsperf bukan merupakan indikasi, dan semuanya tergantung pada browser Anda dan / atau versi OS, atau dalam keadaan tertentu dari mesin saat ini pada saat tertentu.
ocramot
33

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 undefinedpada 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...

var foo = 1;
function bar() {
  if (!foo) {
    var foo = 10 }
  return foo; }
bar() // 10

Variabel fooyang mengangkat ke atas fungsi, diinisialisasi ke undefined, sehingga !fooadalah true, begitu fooditugaskan 10. Bagian fooluar barruang lingkup tidak memainkan peran dan tidak 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 deklarasi fungsi terakhir "menempel".

function f() {
  var a = 4;
  function a() {return 1}; 
  function a() {return 2}; 
  return a; }
f() // 4

Dalam contoh aini diinisialisasi dengan objek fungsi yang dihasilkan dari mengevaluasi deklarasi fungsi kedua, dan kemudian ditugaskan 4.

var a = 1;
function b() {
  a = 10;
  return;
  function a() {}}
b();
a // 1

Di sini deklarasi fungsi diangkat terlebih dahulu, mendeklarasikan dan menginisialisasi variabel a. Selanjutnya, variabel ini ditugaskan 10. Dengan kata lain: tugas tidak ditugaskan ke variabel luar a.

Eljenso
sumber
3
Anda memiliki cara yang agak aneh untuk menempatkan kawat gigi penutup. Apakah Anda seorang pembuat kode Python? Sepertinya Anda mencoba membuat Javascript terlihat seperti Python. Saya khawatir ini membingungkan orang lain. Jika saya harus mempertahankan kode JavaScript Anda, saya akan membiarkan kode Anda melalui prettyprinter otomatis terlebih dahulu.
nalply
1
Pos luar biasa. 'Fungsi yang dapat dieksekusi sendiri' atau 'ekspresi fungsi yang segera dipanggil' harus cukup mudah dilihat dan preferensi gayanya tidak boleh mengurangi posnya - yang akurat dan merangkum 'mengangkat' dengan sempurna. +1
Ricalsin
32

Contoh pertama adalah deklarasi fungsi:

function abc(){}

Contoh kedua adalah ekspresi fungsi:

var abc = function() {};

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:

//this will work
abc(param);
function abc(){}

//this would fail
abc(param);
var abc = function() {}

Untuk mempelajari lebih lanjut tentang topik ini, saya sangat merekomendasikan Anda tautan ini

budak
sumber
1
Contoh Anda sama dengan jawaban teratas
GôTô
Alasan utama untuk memposting jawaban ini adalah untuk menyediakan tautan di bagian bawah. Ini adalah bagian yang hilang bagi saya untuk sepenuhnya memahami pertanyaan di atas.
sla55er
1
Sangat keren bahwa Anda ingin membagikan tautannya. Tetapi tautan ke informasi tambahan, dalam SO, seharusnya hanya berupa komentar pada pertanyaan atau jawaban favorit Anda. Sangat tidak optimal untuk mengacaukan halaman yang panjang dan rumit seperti ini dengan informasi berulang hanya untuk menambahkan satu tautan yang bermanfaat di bagian akhir. Tidak, Anda tidak akan mendapatkan poin rep untuk memberikan tautan, tetapi Anda akan membantu komunitas.
XML
31

Dalam hal biaya pemeliharaan kode, fungsi-fungsi yang disebutkan lebih disukai:

  • Independen dari tempat di mana mereka dinyatakan (tetapi masih dibatasi oleh ruang lingkup).
  • Lebih tahan terhadap kesalahan seperti inisialisasi bersyarat (Anda masih dapat mengesampingkan jika ingin).
  • Kode menjadi lebih mudah dibaca dengan mengalokasikan fungsi lokal secara terpisah dari fungsionalitas ruang lingkup. Biasanya dalam ruang lingkup fungsinya berjalan lebih dulu, diikuti oleh deklarasi fungsi lokal.
  • Dalam debugger Anda akan melihat dengan jelas nama fungsi pada tumpukan panggilan alih-alih fungsi "anonim / dievaluasi".

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:

{
    member:function() { /* How do I make "this.member" a named function? */
    }
}
Sasha Firsov
sumber
2
Ada tes untuk mengonfirmasi: blog.firsov.net/2010/01/... Uji kinerja JS - ruang lingkup dan fungsi yang dinamai - Analytics
Sasha Firsov
25

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 ).

Kafka
sumber
Pada ES2015 (enam setengah tahun setelah jawaban Anda diposting), kedua fungsi dalam pertanyaan tersebut dinamai.
TJ Crowder
25

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.

Herc
sumber
25

Jawaban Greg sudah cukup baik, tetapi saya masih ingin menambahkan sesuatu yang saya pelajari tadi dengan memperhatikan jawaban Douglas Crockford video .

Ekspresi fungsi:

var foo = function foo() {};

Pernyataan fungsi:

function foo() {};

Pernyataan fungsi hanyalah singkatan untuk varpernyataan dengan afunction nilai.

Begitu

function foo() {};

meluas ke

var foo = function foo() {};

Yang berkembang lebih jauh ke:

var foo = undefined;
foo = function foo() {};

Dan mereka berdua diangkat ke atas kode.

Tangkapan layar dari video

Rohan
sumber
7
Maaf tapi ini tidak benar - Saya tidak tahu apa yang ingin dikatakan Crockford dalam slide itu. Deklarasi fungsi & variabel selalu diangkat ke atas cakupannya. Perbedaannya adalah bahwa penugasan variabel (apakah Anda menugaskannya dengan string, boolean atau fungsi) tidak diangkat ke atas sedangkan badan fungsi (menggunakan deklarasi fungsi).
Thomas Heymann
Lihatlah contoh-contoh kode ini: gist.github.com/cyberthom/36603fbc20de8e04fd09
Thomas Heymann
24

Ada empat perbandingan penting antara dua deklarasi fungsi yang berbeda seperti yang tercantum di bawah ini.

  1. Ketersediaan (ruang lingkup) fungsi

Berikut ini berfungsi karena function add()dicakup ke blok terdekat:

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

function add(a, b){
  return a + b;
}

Berikut ini tidak berfungsi karena variabel dipanggil sebelum nilai fungsi ditugaskan ke variabel add.

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function(a, b){
  return a + b;
}

Kode di atas identik dalam fungsionalitas dengan kode di bawah ini. Perhatikan bahwa penetapan secara eksplisit add = undefinedtidak perlu karena hanya melakukan var add;adalah sama persis dengan var add=undefined.

var add = undefined;

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

add = function(a, b){
  return a + b;
}

Berikut ini tidak berfungsi karena var add=mengunggulkan function add().

try {
  console.log("Success: ", add(1, 1));
} catch(e) {
  console.log("ERROR: " + e);
}

var add=function add(a, b){
  return a + b;
}

  1. (fungsi) .name

Nama fungsi function thefuncname(){}adalah thefuncname ketika dinyatakan dengan cara ini.

function foobar(a, b){}

console.log(foobar.name);

var a = function foobar(){};

console.log(a.name);

Jika tidak, jika suatu fungsi dinyatakan sebagai function(){}, fungsi .name adalah variabel pertama yang digunakan untuk menyimpan fungsi.

var a = function(){};
var b = (function(){ return function(){} });

console.log(a.name);
console.log(b.name);

Jika tidak ada variabel yang diatur ke fungsi, maka nama fungsi adalah string kosong ( "").

console.log((function(){}).name === "");

Terakhir, ketika variabel fungsi ditugaskan untuk awalnya menetapkan nama, variabel berturut-turut diatur ke fungsi tidak mengubah nama.

var a = function(){};
var b = a;
var c = b;

console.log(a.name);
console.log(b.name);
console.log(c.name);

  1. Performa

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).

  1. Mutabilitas yang berubah-ubah

Ketika Anda menggunakan varkata kunci untuk mendeklarasikan variabel, Anda kemudian dapat menetapkan kembali nilai yang berbeda untuk variabel seperti itu.

(function(){
    "use strict";
    var foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

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 melakukannya arr[10] = "example". Hanya melakukan sesuatu seperti arr = "new value"atau arr = []akan melakukan kesalahan seperti yang terlihat di bawah ini.

(function(){
    "use strict";
    const foobar = function(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

Menariknya, jika kita mendeklarasikan variabel sebagai function funcName(){}, maka immutabilitas variabel sama dengan mendeklarasikannya var.

(function(){
    "use strict";
    function foobar(){}; // initial value
    try {
        foobar = "Hello World!"; // new value
        console.log("[no error]");
    } catch(error) {
        console.log("ERROR: " + error.message);
    }
    console.log(foobar, window.foobar);
})();

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 seperti var functionName = function() {}ketika di blok non-penutupan untuk barang-barang di luar kata penutupan. Mengamati.

  • Normal var add=function(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}');
  }
} catch(e) {
  console.log("Is a block");
}
var add=function(a, b){return a + b}

  • Normal function add(){}

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
function add(a, b){
  return a + b;
}

  • Fungsi

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(function () {
    function add(a, b){
      return a + b;
    }
})();

  • Pernyataan (seperti if, else, for, while, try/ catch/ finally, switch, do/ while, with)

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
{
    function add(a, b){
      return a + b;
    }
}

  • Fungsi Panah dengan var add=function()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    var add=function(a, b){
      return a + b;
    }
})();

  • Fungsi Panah Dengan function add()

try {
  // typeof will simply return "undefined" if the variable does not exist
  if (typeof add !== "undefined") {
    add(1, 1); // just to prove it
    console.log("Not a block");
  }else if(add===undefined){ // this throws an exception if add doesn't exist
    console.log('Behaves like var add=function(a,b){return a+b}')
  }
} catch(e) {
  console.log("Is a block");
}
(() => {
    function add(a, b){
      return a + b;
    }
})();

Jack Giffin
sumber
Ini layak menjadi jawaban yang diterima dan paling banyak dipilih
Aaron John Sabu
18

@EugeneLazutkin memberikan contoh di mana ia menamai fungsi yang ditugaskan untuk dapat digunakanshortcut() 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)

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 menyebutkan fungsi yang akan dipanggil secara rekursif, tes akan berlalu. (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." );
Joel Purra
sumber
17

Perbedaan lain yang tidak disebutkan dalam jawaban lain adalah jika Anda menggunakan fungsi anonim

var functionOne = function() {
    // Some code
};

dan menggunakannya sebagai konstruktor seperti pada

var one = new functionOne();

maka one.constructor.nametidak akan didefinisikan. Function.nametidak standar tetapi didukung oleh Firefox, Chrome, browser lain yang diturunkan dari Webkit dan IE 9+.

Dengan

function functionTwo() {
    // Some code
}
two = new functionTwo();

adalah mungkin untuk mengambil nama konstruktor sebagai string two.constructor.name.

Ingo Kegel
sumber
Nama dalam kasus pertama tidak akan ditentukan karena fungsi anonimnya ditugaskan ke variabel. Saya pikir kata anonim diciptakan untuk hal-hal yang tidak memiliki nama mereka :)
Om Shankar
Dalam contoh ini, dua = baru menjadi fungsi global karena tidak ada var
Waqas Tahir
16

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 variabel doSomething,. 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.

function foo() {
    return 3;
}

ECMA 5 (13,0) mendefinisikan sintaks sebagai
fungsi Identifier (FormalParameterList opt ) {} FunctionBody

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".

// 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 sintaksis sebagai
function Identifier opt (formalParameterList opt ) {FunctionBody}

NullPoiиteя
sumber
16

Saya mencantumkan perbedaan di bawah ini:

  1. 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:

    function outerFunction() {
        function foo() {
           return 1;
        }
        return foo();
        function foo() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 2

    Ini karena, selama eksekusi, sepertinya: -

    function foo() {  // The first function declaration is moved to top
        return 1;
    }
    function foo() {  // The second function declaration is moved to top
        return 2;
    }
    function outerFunction() {
        return foo();
    }
    alert(outerFunction()); //So executing from top to bottom,
                            //the last foo() returns 2 which gets displayed

    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:

    function outerFunction() {
        var foo = function() {
           return 1;
        }
        return foo();
        var foo = function() {
           return 2;
        }
    }
    alert(outerFunction()); // Displays 1

    Ini karena selama eksekusi, sepertinya:

    function outerFunction() {
       var foo = undefined;
       var foo = undefined;
    
       foo = function() {
          return 1;
       };
       return foo ();
       foo = function() {   // This function expression is not reachable
          return 2;
       };
    }
    alert(outerFunction()); // Displays 1
  2. Tidak aman untuk menulis deklarasi fungsi dalam blok non-fungsi seperti jika karena mereka tidak akan dapat diakses.

    if (test) {
        function x() { doSomething(); }
    }
  3. Ekspresi fungsi yang dinamai seperti di bawah ini, mungkin tidak berfungsi di browser Internet Explorer sebelum versi 9.

    var today = function today() {return new Date()}
varna
sumber
1
@ Arjun Apa masalah jika pertanyaan diajukan bertahun-tahun sebelumnya? Sebuah jawaban tidak hanya menguntungkan OP tetapi juga semua pengguna SO, tidak peduli kapan pertanyaan diajukan. Dan apa yang salah dengan menjawab pertanyaan yang sudah memiliki jawaban yang diterima?
SantiBailors
1
@ Arjun Anda harus mengerti menjawab pertanyaan lama itu tidak buruk. Jika itu terjadi, SO akan memiliki penghalang seperti itu. Bayangkan ada perubahan pada API (walaupun tidak dalam konteks pertanyaan ini) dan seseorang melihatnya dan memberikan jawaban dengan API baru, bukankah itu diizinkan ?? Sampai dan kecuali jawabannya tidak masuk akal dan tidak ada di sini, jawaban akan dihapus dan dihapus secara otomatis. Anda tidak perlu repot dengan itu !!!!
Sudhansu Choudhary
15

Jika Anda akan menggunakan fungsi-fungsi itu untuk membuat objek, Anda akan mendapatkan:

var objectOne = new functionOne();
console.log(objectOne.__proto__); // prints "Object {}" because constructor is an anonymous function

var objectTwo = new functionTwo();
console.log(objectTwo.__proto__); // prints "functionTwo {}" because constructor is a named function
Pawel Furmaniak
sumber
Saya sepertinya tidak bisa mereproduksi ini. console.log(objectOne.__proto__);mencetak "functionOne {}" di konsol saya. Adakah gagasan mengapa ini bisa terjadi?
Mike
Sepertinya saya tidak bisa mereproduksi juga.
daremkd
1
Ini adalah kemampuan debugger Anda (untuk menampilkan "kelas" dari objek yang dicatat), dan sebagian besar yang dapat memperoleh nama bahkan untuk ekspresi fungsi anonim hari ini. Btw, Anda harus memperjelas bahwa tidak ada perbedaan fungsional antara kedua instance.
Bergi
12

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 ...

[].forEach(function iterator() {});

Tetapi sebagian besar itu tidak perlu ditekankan.

Harness ( Biola )

'use strict';

var a = function () {
    throw new Error();
},
    b = function b() {
        throw new Error();
    },
    c = function d() {
        throw new Error();
    },
    e = {
        f: a,
        g: b,
        h: c,
        i: function () {
            throw new Error();
        },
        j: function j() {
            throw new Error();
        },
        k: function l() {
            throw new Error();
        }
    },
    m = (function () {
        return function () {
            throw new Error();
        };
    }()),
    n = (function () {
        return function n() {
            throw new Error();
        };
    }()),
    o = (function () {
        return function p() {
            throw new Error();
        };
    }());

console.log([a, b, c].concat(Object.keys(e).reduce(function (values, key) {
    return values.concat(e[key]);
}, [])).concat([m, n, o]).reduce(function (logs, func) {

    try {
        func();
    } catch (error) {
        return logs.concat('func.name: ' + func.name + '\n' +
                           'Trace:\n' +
                           error.stack);
        // Need to manually log the error object in Nitro.
    }

}, []).join('\n\n'));

V8

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at a (http://localhost:8000/test.js:4:11)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: b
Trace:
Error
    at b (http://localhost:8000/test.js:7:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: d
Trace:
Error
    at d (http://localhost:8000/test.js:10:15)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at e.i (http://localhost:8000/test.js:17:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: j
Trace:
Error
    at j (http://localhost:8000/test.js:20:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: l
Trace:
Error
    at l (http://localhost:8000/test.js:23:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: 
Trace:
Error
    at http://localhost:8000/test.js:28:19
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: n
Trace:
Error
    at n (http://localhost:8000/test.js:33:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27

func.name: p
Trace:
Error
    at p (http://localhost:8000/test.js:38:19)
    at http://localhost:8000/test.js:47:9
    at Array.reduce (native)
    at http://localhost:8000/test.js:44:27 test.js:42

Monyet laba-laba

func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
a@http://localhost:8000/test.js:4:5
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: b
Trace:
b@http://localhost:8000/test.js:7:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: d
Trace:
d@http://localhost:8000/test.js:10:9
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
e.i@http://localhost:8000/test.js:17:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: j
Trace:
j@http://localhost:8000/test.js:20:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: l
Trace:
l@http://localhost:8000/test.js:23:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: 
Trace:
m</<@http://localhost:8000/test.js:28:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: n
Trace:
n@http://localhost:8000/test.js:33:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1


func.name: p
Trace:
p@http://localhost:8000/test.js:38:13
@http://localhost:8000/test.js:47:9
@http://localhost:8000/test.js:54:1

Cakra

func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at a (http://localhost:8000/test.js:4:5)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at b (http://localhost:8000/test.js:7:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at d (http://localhost:8000/test.js:10:9)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at e.i (http://localhost:8000/test.js:17:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at j (http://localhost:8000/test.js:20:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at l (http://localhost:8000/test.js:23:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at Anonymous function (http://localhost:8000/test.js:28:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at n (http://localhost:8000/test.js:33:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)


func.name: undefined
Trace:
Error
   at p (http://localhost:8000/test.js:38:13)
   at Anonymous function (http://localhost:8000/test.js:47:9)
   at Global code (http://localhost:8000/test.js:42:1)

Nitro

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
a@http://localhost:8000/test.js:4:22
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: b
Trace:
b@http://localhost:8000/test.js:7:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: d
Trace:
d@http://localhost:8000/test.js:10:26
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
i@http://localhost:8000/test.js:17:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: j
Trace:
j@http://localhost:8000/test.js:20:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: l
Trace:
l@http://localhost:8000/test.js:23:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: 
Trace:
http://localhost:8000/test.js:28:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: n
Trace:
n@http://localhost:8000/test.js:33:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33

func.name: p
Trace:
p@http://localhost:8000/test.js:38:30
http://localhost:8000/test.js:47:13
reduce@[native code]
global code@http://localhost:8000/test.js:44:33
Jackson
sumber
12

Dalam JavaScript ada dua cara untuk membuat fungsi:

  1. Deklarasi fungsi:

    function fn(){
      console.log("Hello");
    }
    fn();

    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.

  2. Ekspresi fungsi:

    var fn=function(){
      console.log("Hello");
    }
    fn();

    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 () {}

Anoop Rai
sumber
1
bagaimana dengan opsi ketiga , var fn = function fn() {...}?
chharvey
Hai Chharvey, tidak yakin tentang pertanyaan Anda, saya kira Anda berbicara tentang ekspresi fungsi yang telah saya sebutkan. Namun, jika masih ada beberapa kebingungan hanya akan lebih rumit.
Anoop Rai
ya saya bertanya tentang ekspresi fungsi bernama . ini mirip dengan pilihan Anda # 2 kecuali bahwa fungsi tersebut memiliki pengidentifikasi. biasanya pengidentifikasi ini sama dengan variabel yang ditugaskan kepadanya, tetapi tidak selalu demikian.
chharvey
1
Ya Ekspresi fungsi Bernama mirip dengan opsi saya # 2. Baik memiliki pengenal tidak wajib karena tidak digunakan. Kapan pun Anda akan menjalankan ekspresi fungsi, Anda akan menggunakan variabel yang menahan objek fungsi. Pengidentifikasi tidak memiliki tujuan.
Anoop Rai
11

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 .

functionOne();
var functionOne = function() {
    // Some code
};

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.

functionOne();
function functionOne() {
   // Some code
}
Nitin9791
sumber
11

Tentang kinerja:

Versi baru V8memperkenalkan beberapa optimasi di bawah tenda dan begitu juga SpiderMonkey.

Hampir tidak ada perbedaan sekarang antara ekspresi dan deklarasi.
Ekspresi fungsi tampaknya lebih cepat sekarang.

Chrome 62.0.3202 Tes Chrome

FireFox 55 Tes Firefox

Chrome Canary 63.0.3225 Tes Canary Chrome


Anonymousekspresi fungsi tampaknya memiliki kinerja yang lebih baik terhadap Namedekspresi fungsi.


Firefox Chrome Canary ChromeFirefox bernama_anonymous Kenari Chrome bernama_anonymous Chrome bernama_anonim

Panos Kal.
sumber
1
Ya, perbedaan ini sangat signifikan yang diharapkan devs akan menyibukkan diri dengan pendekatan mana yang lebih dipertahankan untuk kebutuhan khusus mereka daripada yang satu mungkin lebih cepat (Anda akan mendapatkan hasil jsperf yang berbeda pada masing-masing mencoba tergantung pada apa browser lakukan - sebagian besar tugas javascript tidak perlu melibatkan diri dengan optimasi mikro sampai tingkat ini).
squidbe
@squidbe Tidak ada perbedaan. Lihat di sini: jsperf.com/empty-tests-performance
Jack Giffin
10

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

var functionOne = function() {
    // Some code
};

Function Expression mendefinisikan fungsi sebagai bagian dari sintaks ekspresi yang lebih besar (biasanya penugasan variabel). Fungsi yang didefinisikan melalui Ekspresi Fungsi dapat dinamai atau anonim. Ekspresi Fungsi tidak boleh dimulai dengan "function" (karenanya tanda kurung di sekitar contoh pemanggilan sendiri di bawah ini).

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

function functionTwo() {
    // Some code
}

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. Sangat membantu untuk menganggap mereka sebagai saudara dari Deklarasi Variabel. Sama seperti Deklarasi Variabel harus dimulai dengan "var", Deklarasi Fungsi harus dimulai dengan "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

Alireza
sumber
1
...also this way of declaring is a better way to create Constructor functions in JavaScriptTolong jelaskan, saya penasaran!
Karl Morrison
Salah satu alasannya adalah karena semua fungsi Konstruktor bawaan dalam JavaScript dibuat seperti fungsi ini Number () {[kode asli]} dan Anda tidak perlu bingung dengan yang built-in, juga merujuk nanti dalam kasus ini lebih aman dan Anda mengakhiri kode lebih rapi tetapi tidak menggunakan mengangkat ...
Alireza
8

Ini hanya dua cara yang mungkin untuk mendeklarasikan fungsi, dan dengan cara kedua, Anda dapat menggunakan fungsi sebelum deklarasi.

Tao
sumber
7

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.

var func = new Function("x", "y", "return x*y;");
function secondFunction(){
   var result;
   result = func(10,20);
   console.log ( result );
}

secondFunction()
SuperNova
sumber
Meskipun ini baik dan benar, bagaimana tepatnya hal ini saja berhubungan dengan pertanyaan yang diajukan?
Jack Giffin