Bir işlev döndüren işlevler


110

Bu 'İşlevleri döndüren işlevler' kavramına takılı kaldım. Stoyan Stefanov'un 'Object Oriented Javascript' kitabına atıfta bulunuyorum.

Snippet Bir:

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

Çıktı:

A!
B!
break

Snippet İki

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

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

    return b;
}

var s = a();
alert('break');
s();
Çıktı:

A!
break
B!

Birisi bana dönen arasındaki farkı söyleyebilir bve b()yukarıdaki snippet'lerdeki?


2
İlk parçacığın s () üzerinde bir hata verdiğini fark edeceksiniz;
weirdalsuperfan

Yanıtlar:


122

Bir işleve bir değişken atamak (parantez olmadan) işleve gönderimi kopyalar. Bir işlev adının sonuna parantez koymak, işlevi çağırır ve işlevin dönüş değerini döndürür.

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());

Örneğinizde, bir işlev içindeki işlevleri de tanımlıyorsunuz. Gibi:

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

İşlev hala çağrılabilir. Hala var. Bu, JavaScript'te her zaman kullanılır. Fonksiyonlar etrafında geçirilebilir sadece diğer değerler gibi. Aşağıdakileri göz önünde bulundur:

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

Fonksiyon sayısı, dışında tanımlanan değişkenleri tutabilir. Buna kapatma denir. JavaScript'te de çok kullanılır.


Snippet Bir: var hero = {name: 'Rafaelo', sayName: function () {return hero.name; }, nayName: hero.sayName} hero.nayName (); Snippet İki: var hero = {name: 'Rafaelo', sayName: function () {return hero.name; }, nayName: this.sayName} hero.nayName (); İlk pasaj bana doğru çıktıyı verirken ikincisi vermiyor. Neden? Saygılarımızla.
Cafecorridor

thisyalnızca bir işlev gövdesi içindeki bir şey anlamına gelir, aksi takdirde küreseldir. Söylediğin şey this.sayName, küresel değişkeni istemiyorsun sayNameki var olmayan, tanımsız, yani çağrılabilir değil.
kzh

8
D () () ile kafam karıştı; ilk başta ama sonra fark etti ki ilk () d'yi çağırdı ve ikincisi () d'nin dönüş değerini çağırdı, yani e.
2014

1
Sekiz yıl sonra ve bu hala geçerli!
Brad Vanderbush

45

İşlev adını döndürmeden döndürmek, ()yaptığınız gibi atanabilen işleve bir başvuru döndürür var s = a(). sartık işleve bir başvuru içerir b()ve çağırma s()işlevsel olarak çağırmaya eşdeğerdir b().

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

İşlevin ()bir return deyiminde çağrılması işlevi çalıştırır ve işlev tarafından döndürülen değeri döndürür. Aramaya benzer var x = b();, ancak dönüş değerini atamak yerine b()onu çağıran işlevden döndürürsünüz a(). İşlevin b()kendisi bir değer döndürmezse, undefinedbaşka bir iş ne yapılırsa yapılsın çağrı geri döner 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;

1
Tüm cevaplar arasında, basitliğinden dolayı cevabınızı daha çok beğendim.
anar khalilov

Peki koy! Bu cevabı anlamak çok kolay.
AndrewSteinheiser

İşlev çağrının tanımsız döndürdüğü bir değer döndürmezse hakkındaki biti doğruladığınız için teşekkür ederiz. Bu karışıklığı son zamanlarda keşfettim: işlev açıkça null döndürse bile, bir değişkene döndürülen değeri atarsanız, null değil, tanımsız olacaktır. Bunun bazı kod tabanlarında pek çok tuhaf soruna yol açtığını düşünüyorum, çünkü null ve undefined kesinlikle === ile eşdeğer değildir.
Benjamin

37

return b(); b () işlevini çağırır ve sonucunu döndürür.

return b; daha sonra çağırmak üzere bir değişkende saklayabileceğiniz b işlevine bir başvuru döndürür.


17

Geri bdönmek, bir fonksiyon nesnesi döndürmektir. Javascript'te, diğer nesneler gibi işlevler de nesnelerdir. Bunu yararlı bulmazsanız, "nesne" kelimesini "şey" ile değiştirin. Bir işlevden herhangi bir nesneyi iade edebilirsiniz. Doğru / yanlış bir değer döndürebilirsiniz. Bir tam sayı (1,2,3,4 ...). Bir dizge döndürebilirsiniz. Birden çok özelliğe sahip karmaşık bir nesneyi döndürebilirsiniz. Ve bir işlevi döndürebilirsiniz. bir işlev sadece bir şeydir.

Sizin durumunuzda, geri bdönmek bir şeyi döndürür, şey çağrılabilir bir işlevdir. Döndürmek b(), çağrılabilir işlev tarafından döndürülen değeri döndürür.

Bu kodu düşünün:

function b() {
   return 42;
}

Yukarıdaki tanımı kullanarak return b();42 değerini döndürür. Öte yandan return b;, kendisi 42 değerini döndüren bir işlev döndürür. Bunlar iki farklı şeydir.


4
geri dönmelidir 42;)
c69

4

Geri döndüğünüzde b, bu sadece b işlevine bir referanstır, ancak şu anda çalıştırılmamaktadır.

Döndüğünüzde b(), işlevi çalıştırıyor ve değerini döndürüyorsunuz.

Deneyin alerting typeof(s)sizin örneklerde. Snippet b size 'işlev' verecektir. Bir pasaj size ne verecek?


Birincisi 'tanımsız' verir. B () dönüşünün tamamen yararsız olduğu anlamına mı geliyor? Ayrıca, ikinci parçada b işlevi özeldir. O halde, fonksiyonun dışındaki referansa nasıl erişebiliriz? Lütfen mümkünse bu kavramı net bir şekilde açıklayan bir bağlantı sağlayın. Teşekkürler!
Cafecorridor

İlkinin cevabını aldım. fonksiyon b () 'de 1 + 2 döndürür ve typeof sayıyı gösterir. Teşekkürler.
Cafecorridor

Anladığına sevindim! Özel işlevle ilgili olarak: İkinci örnekte, onu zaten döndürdüğünüz için gerçekten özel değildir. Aslında, atanır s. return thisBunun yerine deneyin return bs.b()O zaman yapabileceksiniz ;)
vzwick

Kesinlikle deneyeceğim. Javascript'te bu konsepte henüz ulaşmadım. Belki birkaç gün içinde. Teşekkürler! :)
Cafecorridor

function a () {alert ("A!"); fonksiyon b () {uyarı ("B!"); } dönüş b; } var s = a (); sil a; s (); ---- son ---- Javascript'teki referans kavramı Java'daki ile aynı mı? Burada a () işlevini sildim ve yine de bir s () çağrısı b () 'yi çalıştırıyor. Öyleyse s'nin b'nin bir kopyasını içerdiğini ve a () 'da tanımlanan b ()' yi göstermediğini söyleyebilir miyim?
Cafecorridor

2

Fonksiyonu int gibi bir tür olarak hayal edin. İnt'leri bir işlevde döndürebilirsiniz. İşlevleri de döndürebilirsiniz, bunlar "işlev" türünde nesnelerdir.

Şimdi sözdizimi problemi: işlevler değer döndürdüğü için, bir işlevi nasıl döndürür ve değer döndürmez?

parantezleri atlayarak! Çünkü parantez olmadan işlev çalıştırılmayacaktır! Yani:

return b;

"İşlevi" döndürür (bir sayı döndürüyormuşsunuz gibi düşünün), ancak:

return b();

Önce işlevi çalıştırır, sonra onu çalıştırarak elde edilen değeri döndürür, bu büyük bir fark!


İkinci parçada, işlev b özeldir. O halde, fonksiyonun dışındaki referansa nasıl erişebiliriz? Aynı şeyi yöneten herhangi bir kural var mı?
Cafecorridor

JavaScript'teki nesneler (bu, işlevleri içerir), onları paylaşırsanız artık özel değildir.
kzh

@Cafecorridor: Eğer özel işlev bir şey (bir genel işlev) tarafından döndürülmüşse veya bir genel değişkene (yani, uygulama tarafından erişilebilir bir değişken) atanmışsa, kendi değişkeninizi () kolayca yapabilirsiniz ; aksi takdirde bir değişkene döndürülen işlevi atayın ve yourvariable ();
Francesco Belladonna

2

Bir değişken oluşturun :

var thing1 = undefined;

Bir İşlev Bildirin :

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

Uyarın değeri arasında thing1(bizim ilk değişken):

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

Şimdi, işleve thing1bir referans olmak isteseydik something1, yani yarattığımız işlevle aynı şey olurdu, yapardık:

thing1 = something1;

Bununla birlikte, eğer fonksiyonun return değerini istiyorsak, o zaman ona yürütülen fonksiyonun dönüş değerini atamalıyız. Fonksiyonu parantez kullanarak çalıştırırsınız:

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

-1

Snippet bir:

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

'b ()' ifadesi, 'B!' metnini içeren bir iletişim kutusunu gösteren 'b' adlı işlevi çalıştırmak anlamına gelir.

'return b ()' ifadesi; 'b' adlı bir işlevi yürütmek ve sonra hangi 'b' işlevinin döndüğünü döndürmek anlamına gelir. ama 'b' hiçbir şey döndürmez, sonra bu 'return b ()' ifadesi de hiçbir şey döndürmez. Eğer b () bir sayı döndürürse, o zaman 'dönüş b ()' de bir sayıdır.

Şimdi 's', 'a ()' dönüşünün değeri atanır, bu da 'b ()' döndürür, bu hiçbir şey değildir, yani 's' hiçbir şeydir (JavaScript'te bu aslında bir şeydir, 'tanımsız''dır. JavaScript'ten "s" nin hangi veri türünü yorumlamasını istediğinizde, JavaScript yorumlayıcısı size "s" nin tanımsız olduğunu söyleyecektir.) "s" tanımsız olduğundan, JavaScript'ten bu ifadeyi "s ()" yürütmesini istediğinizde, JavaScript'ten 's' adlı bir işlevi çalıştırmasını istiyorsunuz, ancak burada 's' bir işlev değil, 'tanımsız', bu nedenle JavaScript şikayet edecek, "hey, s bir işlev değil, nasıl olduğunu bilmiyorum bunun için "Yakalanmamış TypeError: s bir işlev değildir" hata mesajı JavaScript tarafından gösterilir (Firefox ve Chrome'da test edilmiştir)


Snippet İki

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

şimdi, 'a' işlevi 'b' adlı bir işleve bir işaretçi / takma adı döndürür. bu nedenle 's = a ()' çalıştırıldığında, 's' b'yi gösteren bir değer alır, yani 's' şimdi 'b'nin bir takma adıdır,' s 'çağrısı' b 'çağrısına eşittir. yani 's' artık bir işlevdir. 'S ()' çalıştırmak, 'b' işlevini çalıştırmak anlamına gelir ('b ()' ile aynı), 'B!' görünecektir (yani 'uyarı (' B! ');' b 'fonksiyonundaki ifade)


-2

Bu gerçek hayatta çok kullanışlıdır.

Express.js ile çalışma

Yani normal expressrotanız şöyle görünür:

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

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

Peki ya bir paketleyici, hata işleyici veya smth eklemeniz gerekirse?

Sonra işlevinizi bir sarmalayıcıdan çağırırsınız.

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

Karmaşık görünüyor mu? Peki şuna ne dersin?

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

Eğer bir işlev geçiyoruz sonunda Bkz loggingWrapperbirbirini fonksiyonu olarak tartıştığını itWorksHandler, ve loggingWrapperdöner götüren yeni işlev req, res, nextbağımsız değişkenleri olarak.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.