Fungsi yang mengembalikan fungsi

110

Saya terjebak dengan konsep 'Fungsi yang mengembalikan fungsi'. Saya merujuk pada buku 'Object Oriented Javascript' oleh Stoyan Stefanov.

Cuplikan Satu:

    function a() {
      
        alert('A!');
    
        function b(){
            alert('B!'); 
        }
    
        return b();
    }
    
    var s = a();
    alert('break');
    s();

Keluaran:

A!
B!
break

Cuplikan Dua

function a() {
  
    alert('A!');

    function b(){
        alert('B!'); 
    }

    return b;
}

var s = a();
alert('break');
s();
Keluaran:

A!
break
B!

Bisakah seseorang memberi tahu saya perbedaan antara kembali bdan b()di cuplikan di atas?

Cafecorridor
sumber
2
Anda akan melihat potongan pertama memberikan kesalahan pada s ();
oddalsuperfan

Jawaban:

122

Menetapkan variabel ke suatu fungsi (tanpa tanda kurung) akan menyalin referensi ke fungsi tersebut. Menempatkan tanda kurung di akhir nama fungsi, memanggil fungsi, mengembalikan nilai hasil fungsi.

Demo

function a() {
    alert('A');
}
//alerts 'A', returns undefined

function b() {
    alert('B');
    return a;
}
//alerts 'B', returns function a

function c() {
    alert('C');
    return a();
}
//alerts 'C', alerts 'A', returns undefined

alert("Function 'a' returns " + a());
alert("Function 'b' returns " + b());
alert("Function 'c' returns " + c());

Dalam contoh Anda, Anda juga mendefinisikan fungsi dalam suatu fungsi. Seperti:

function d() {
    function e() {
        alert('E');
    }
    return e;
}
d()();
//alerts 'E'

Fungsinya masih bisa dipanggil. Itu masih ada. Ini digunakan di JavaScript sepanjang waktu. Fungsi dapat diedarkan hanya seperti nilai-nilai lain. Pertimbangkan hal berikut:

function counter() {
    var count = 0;
    return function() {
        alert(count++);
    }
}
var count = counter();
count();
count();
count();

Hitungan fungsi dapat menyimpan variabel yang didefinisikan di luarnya. Ini disebut penutupan. Ini juga banyak digunakan dalam JavaScript.

kzh
sumber
Cuplikan Satu: var hero = {name: 'Rafaelo', sayName: function () {return hero.name; }, nayName: hero.sayName} hero.nayName (); Cuplikan Dua: var hero = {name: 'Rafaelo', sayName: function () {return hero.name; }, nayName: this.sayName} hero.nayName (); Potongan pertama memberi saya keluaran yang benar sedangkan yang kedua tidak. Mengapa? Salam.
Cafecorridor
thishanya berarti sesuatu di dalam tubuh fungsi, jika tidak maka global. Maksud Anda this.sayNameadalah bahwa Anda menginginkan variabel global sayNameyang tidak ada, tidak ditentukan, jadi tidak dapat dipanggil.
kzh
7
Saya bingung dengan d () (); pada awalnya tetapi kemudian menyadari bahwa yang pertama () memanggil d dan yang kedua () memanggil nilai kembali d, yaitu e.
skud
1
Delapan tahun kemudian dan ini masih relevan!
Brad Vanderbush
45

Mengembalikan nama fungsi tanpa ()mengembalikan referensi ke fungsi tersebut, yang dapat ditetapkan setelah Anda selesai var s = a(). ssekarang berisi referensi ke fungsi tersebut b(), dan pemanggilan s()secara fungsional setara dengan pemanggilan b().

// Return a reference to the function b().
// In your example, the reference is assigned to var s
return b;

Memanggil fungsi dengan ()pernyataan return akan menjalankan fungsi tersebut, dan mengembalikan nilai apa pun yang dikembalikan oleh fungsi tersebut. Ini mirip dengan memanggil var x = b();, tetapi alih-alih menetapkan nilai kembalian b()Anda mengembalikannya dari fungsi panggilan a(). Jika fungsinya b()sendiri tidak mengembalikan nilai, panggilan akan kembali undefinedsetelah pekerjaan lain apa pun yang dilakukan b().

// Execute function b() and return its value
return b();
// If b() has no return value, this is equivalent to calling b(), followed by
// return undefined;
Michael Berkowski
sumber
1
Dari semua jawaban, saya lebih menyukai jawaban Anda karena kesederhanaannya.
anar khalilov
Bagus! Sangat mudah untuk memahami jawaban ini.
AndrewSteinheiser
Terima kasih telah memvalidasi sedikit tentang jika fungsi tidak mengembalikan nilai yang dikembalikan panggilan tidak ditentukan. Saya menemukan ini mengotak-atik baru-baru ini: bahkan jika fungsi mengembalikan null secara eksplisit, jika Anda menetapkan nilai yang dikembalikan ke variabel itu akan tidak terdefinisi, bukan nol. Saya membayangkan ini menyebabkan banyak masalah aneh di beberapa basis kode, karena null dan undefined tidak sepenuhnya setara dengan ===.
Benjamin
37

return b(); memanggil fungsi b (), dan mengembalikan hasilnya.

return b; mengembalikan referensi ke fungsi b, yang bisa Anda simpan dalam variabel untuk dipanggil nanti.

Abdo
sumber
17

Kembali b adalah mengembalikan objek fungsi. Dalam Javascript, fungsi hanyalah objek, seperti objek lainnya. Jika menurut Anda itu tidak membantu, ganti saja kata "object" dengan "thing". Anda dapat mengembalikan objek apa pun dari suatu fungsi. Anda dapat mengembalikan nilai benar / salah. Integer (1,2,3,4 ...). Anda dapat mengembalikan string. Anda dapat mengembalikan objek kompleks dengan beberapa properti. Dan Anda bisa mengembalikan fungsi. sebuah fungsi hanyalah sebuah benda.

Dalam kasus Anda, mengembalikan bmengembalikan benda, benda itu adalah fungsi yang dapat dipanggil. Mengembalikan b()mengembalikan nilai yang dikembalikan oleh fungsi yang dapat dipanggil.

Pertimbangkan kode ini:

function b() {
   return 42;
}

Menggunakan definisi di atas, return b();mengembalikan nilai 42. Di sisi lain return b;mengembalikan sebuah fungsi, yang dengan sendirinya mengembalikan nilai 42. Mereka adalah dua hal yang berbeda.

Cheeso
sumber
4
itu harus kembali 42;)
c69
4

Saat Anda kembali b, itu hanya referensi ke fungsi b, tetapi tidak dijalankan saat ini.

Saat Anda kembali b(), Anda menjalankan fungsi dan mengembalikan nilainya.

Coba alerting typeof(s)di contoh Anda. Snippet b akan memberi Anda 'fungsi'. Apa yang akan diberikan snippet a kepada Anda?

vzwick.dll
sumber
Yang pertama memberikan 'undefined'. Apakah ini berarti bahwa pengembalian b () sama sekali tidak berguna? Juga, dalam potongan kedua, fungsi b bersifat pribadi. Lalu bagaimana kita dapat mengakses referensi di luar fungsi? Tolong berikan saya tautan yang menjelaskan konsep ini dengan jelas jika memungkinkan. Terima kasih!
Cafecorridor
Saya mendapat jawaban untuk yang pertama. return 1 + 2 dalam fungsi b () dan typeof menunjukkan angka. Terima kasih.
Cafecorridor
Senang Anda mengetahuinya! Adapun fungsi privat: Ini tidak benar-benar privat di contoh kedua karena Anda sudah mengembalikannya. Bahkan, itu ditugaskan ke s. Cobalah return thisalih-alih return b… Anda akan dapat melakukannya s.b();)
vzwick
Saya pasti akan mencobanya. Belum mencapai konsep ini di Javascript. Mungkin dalam beberapa hari. Terima kasih! :)
Cafecorridor
fungsi a () {peringatan ("A!"); fungsi b () {waspada ("B!"); } kembali b; } var s = a (); hapus a; s (); ---- end ---- Apakah konsep referensi di Javascript sama dengan di Java? Di sini saya telah menghapus fungsi a () dan panggilan ke s () mengeksekusi b (). Jadi dapatkah saya mengatakan bahwa s berisi salinan b dan tidak menunjuk ke b () yang ditentukan dalam a ()?
Cafecorridor
2

Bayangkan fungsinya sebagai tipe, seperti int. Anda dapat mengembalikan int dalam suatu fungsi. Anda juga dapat mengembalikan fungsi, mereka adalah objek bertipe "fungsi".

Sekarang masalah sintaks: karena fungsi mengembalikan nilai, bagaimana Anda bisa mengembalikan fungsi dan bukan mengembalikan nilai?

dengan menghilangkan tanda kurung! Karena tanpa tanda kurung, fungsi tidak akan dijalankan! Begitu:

return b;

Akan mengembalikan "fungsi" (bayangkan seperti jika Anda mengembalikan angka), sedangkan:

return b();

Pertama jalankan fungsinya lalu kembalikan nilai yang diperoleh dengan mengeksekusinya, itu perbedaan besar!

Francesco Belladonna
sumber
Dalam potongan kedua, fungsi b bersifat pribadi. Lalu bagaimana kita dapat mengakses referensi di luar fungsi? Apakah ada aturan yang mengatur hal yang sama?
Cafecorridor
Objek di JavaScript (termasuk fungsi) tidak lagi bersifat pribadi jika Anda membagikannya.
kzh
@Cafecorridor: Jika fungsi privat dikembalikan oleh sesuatu (fungsi publik) atau ditugaskan ke variabel publik (baik, variabel yang dapat diakses aplikasi), Anda dapat dengan mudah melakukan variabelAnda (); , jika tidak, tetapkan fungsi yang dikembalikan ke variabel dan lakukan lagi variabel Anda ();
Francesco Belladonna
2

Buat variabel :

var thing1 = undefined;

Deklarasikan Fungsi :

function something1 () {
    return "Hi there, I'm number 1!";
}

Waspada nilai dari thing1(variabel pertama kami):

alert(thing1); // Outputs: "undefined".

Sekarang, jika kita ingin thing1menjadi referensi ke fungsi tersebut something1, artinya itu akan sama dengan fungsi yang kita buat, kita akan melakukan:

thing1 = something1;

Namun, jika kita menginginkan return nilai dari fungsi tersebut maka kita harus menetapkannya nilai kembali dari fungsi yang dieksekusi. Anda menjalankan fungsi dengan menggunakan tanda kurung:

thing1 = something1(); // Value of thing1: "Hi there, I'm number 1!" 
Shaz
sumber
-1

Cuplikan satu:

function a() {
  
    alert('A!');

    function b(){
        alert('B!'); 
    }

    return b(); //return nothing here as b not defined a return value
}

var s = a(); //s got nothing assigned as b() and thus a() return nothing.
alert('break');
s(); // s equals nothing so nothing will be executed, JavaScript interpreter will complain

pernyataan 'b ()' berarti menjalankan fungsi bernama 'b' yang menampilkan kotak dialog dengan teks 'B!'

pernyataan 'return b ();' berarti menjalankan fungsi bernama 'b' dan kemudian mengembalikan fungsi 'b' apa yang dikembalikan. tetapi 'b' tidak menghasilkan apa-apa, maka pernyataan 'return b ()' ini juga tidak mengembalikan apa-apa. Jika b () mengembalikan angka, maka 'return b ()' juga merupakan angka.

Sekarang 's' diberi nilai apa 'a ()' return, yang mengembalikan 'b ()', yang tidak berarti apa-apa, jadi 's' bukan apa-apa (dalam JavaScript itu sebenarnya, itu 'tidak terdefinisi'. Jadi ketika Anda meminta JavaScript untuk menafsirkan tipe data apa 's', penerjemah JavaScript akan memberi tahu Anda 's' adalah tidak terdefinisi.) As 's' adalah tidak terdefinisi, ketika Anda meminta JavaScript untuk mengeksekusi pernyataan ini 's ()', Anda meminta JavaScript untuk menjalankan fungsi bernama 's', tetapi 's' di sini adalah 'tidak ditentukan', bukan fungsi, jadi JavaScript akan mengeluh, "hei, s bukan fungsi, saya tidak tahu caranya untuk dilakukan dengan "s ini, maka pesan kesalahan" Uncaught TypeError: s is not a function "akan ditampilkan oleh JavaScript (diuji di Firefox dan Chrome)


Cuplikan Dua

function a() {
  
    alert('A!');

    function b(){
        alert('B!'); 
    }

    return b; //return pointer to function b here
}

var s = a();  //s get the value of pointer to b
alert('break');
s(); // b() function is executed

sekarang, fungsi 'a' mengembalikan pointer / alias ke fungsi bernama 'b'. jadi ketika mengeksekusi 's = a ()', 's' akan mendapatkan nilai yang menunjuk ke b, yaitu 's' adalah alias dari 'b' sekarang, memanggil 's' sama dengan memanggil 'b'. ie 's' adalah fungsi sekarang. Jalankan 's ()' berarti menjalankan fungsi 'b' (sama seperti menjalankan 'b ()'), kotak dialog yang menampilkan 'B!' akan muncul (yaitu menjalankan 'alert (' B! '); pernyataan dalam fungsi' b ')

Pilot Henry di tempat kerja
sumber
-2

Ini sangat berguna dalam kehidupan nyata.

Bekerja dengan Express.js

Jadi, expressrute reguler Anda terlihat seperti ini:

function itWorksHandler( req, res, next ) {
  res.send("It works!");
}

router.get("/check/works", itWorksHandler );

Tetapi bagaimana jika Anda perlu menambahkan beberapa pembungkus, penanganan kesalahan atau sesuatu?

Kemudian Anda menjalankan fungsi Anda dari pembungkus.

function loggingWrapper( req, res, next, yourFunction ) {
  try {
    yourFunction( req, res );
  } catch ( err ) {
    console.error( err );
    next( err );
  }
}

router.get("/check/works", function( req, res, next ) {
  loggingWrapper( req, res, next, itWorksHandler );
});

Terlihat rumit? Nah, bagaimana dengan ini:

function function loggingWrapper( yourFunction ) => ( req, res, next ) {
  try {
    yourFunction( req, res, next );
  } catch ( err ) {
    console.error( err );
    next( err );
  }
}

router.get("/check/works", loggingWrapper( itWorksHandler ) );

Lihat di bagian akhir Anda meneruskan fungsi yang loggingWrappermemiliki satu argumen sebagai fungsi lain itWorksHandler, dan Anda loggingWrappermengembalikan fungsi baru yang mengambil req, res, nextargumen.

Zilvinas
sumber