"Sonunda" bir dönüş neden "deneyin" i geçersiz kılıyor?


100

Bir dene / yakala bloğu içindeki bir return ifadesi nasıl çalışır?

function example() {
    try {
        return true;
    }
    finally {
        return false;
    }
}

Bu işlevin çıktısının olmasını bekliyorum true, ama onun yerine öyle false!


Diğerleri için, son olarak değil catch bloğunda yanlış dönüş yapın.
habibhassani

Yanıtlar:


95

Sonunda her zaman çalışır . Bunun için, bu da sizin davanızda geri dönüşünün kullanıldığı anlamına geliyor.

Kodunuzu şu şekilde değiştirmek isteyeceksiniz:

function example() { 
    var returnState = false; // initialisation value is really up to the design
    try { 
        returnState = true; 
    } 
    catch {
        returnState = false;
    }
    finally { 
        return returnState; 
    } 
} 

Genel olarak konuşursak, bir fonksiyonda asla birden fazla return ifadesine sahip olmak istemezsiniz, bunun gibi şeyler nedenidir.


47
Birden fazla return ifadesine sahip olmanın her zaman kötü olmadığını iddia ediyorum - Daha fazla tartışma için stackoverflow.com/questions/36707/… adresini ziyaret edin.
Castrohenge

5
Ben de tek dönüş kuralı konusunda aynı fikirde değilim. Nihayet asla geri dönmemelisiniz (C # 'da buna izin bile verilmez).
erikkallen

@erikkallen - bu iyi bir nokta. TCF bloğunun dışında bir dönüş en iyisidir, ancak örnek kod biraz zorlanacaktır :)
annakata

1
@Castrohenge - bu zor ve hızlı bir kural değil, ancak bu iş parçacığındaki çoğu copunter örneği oldukça uydurma ve gördüğüm tek geçerli durum "koruma cümlesidir" (esasen üstteki giriş verilerini kontrol etme modeli) işlev ve koşullu olarak geri dönme). Bu tamamen geçerli bir durum, ancak gerçekten bu dönüşler istisnalar olmalıdır (yine zor ve hızlı değil).
annakata

1
Aslında IE6 ve IE7'de, oldukça ciddi bir tarayıcı hatası nedeniyle nihayet her durumda her zaman çalışmıyor. Spesifik olarak - daha yüksek seviyeli bir try-catch ile çevrili olmayan bir dene-son bloğuna bir istisna atılırsa, en sonunda bloğu çalışmayacaktır. İşte bir test senaryosu jsfiddle.net/niallsmart/aFjKq . Bu sorun IE8'de düzeltildi.
Niall Smart

44

ECMA-262'ye göre (5ed, Aralık 2009), s. 96'da:

Üretim TryStatement : try Block Finallyşu şekilde değerlendirilir:

  1. B Bloğu değerlendirmenin sonucu olsun.
  2. F Son olarak değerlendirmenin sonucu olsun.
  3. F. tipi normalse, B döndür.
  4. Dönüş F.

Ve 36. sayfadan:

Tamamlama tipi (tabloların davranışını açıklamak için kullanılan break, continue, returnve throwkontrol yerel olmayan transfer yerine). Tamamlama türden değerlerin formunun üçe (tip, değer, hedef) , tip biri normal, break, continue, return, ya da throw, bir değer herhangi bir ECMAScript dil bir değer ya da boş ve hedef bir ECMAScript tanımlayıcı veya boş olup.

Bu çok açık return falsetamamlanması tipini belirleyecek nihayet olarak dönüşü neden try ... finallyyapmak 4. Dönüş F .


2
Bu soruya verilen her türden "temelde doğru ama bir şekilde yumuşak ve açıklığa kavuşturmayan" yanıtları okuduktan sonra, bu aslında mantıklı geldi. Anahtar bit, try + catch'in sonunda "ne olursa olsun" (dönüş veya atma veya sadece normal akış), nihayet bölümünü çalıştırırken hatırlanır ve sonra gerçekte yalnızca nihayet sonunda hiçbir şey olmazsa gerçekleşir.
PreventRage

14

Kullandığınızda finally, bu blok içindeki herhangi bir kod, yöntem çıkmadan önce ateşlenir. Eğer bir getiri kullandığınız Çünkü finallybloğu, bu aramaları return falseve öncekinin üstüne return truede tryblokta.

(Terminoloji tam olarak doğru olmayabilir.)


4

Son olarak yeniden yazılan bloklar, blok dönüşünü dener (mecazi anlamda).

Sonunda bir şey döndürürseniz, o zaman işlevden geri döneceğini belirtmek istedim. Ama nihayetinde 'dönüş' sözcüğü yoksa - try bloğundan değer döndürülür;

function example() {
    try {
        return true;
    }
    finally {
       console.log('finally')
    }
}
console.log(example());
// -> finally
// -> true

Yani -son olarak- -try-'nin dönüşünü returnyeniden yazar return.


3

neden yanlış anlıyorsun, sonunda bir blokta geri döndün. nihayet blok her zaman yürütülmelidir. yani return truedeğişikliklerinizreturn false

function example() {
    try {
        return true;
    }
    catch {
        return false;
    }
}

1

Bildiğim kadarıyla, içinde bir ifade olup olmadığına bakılmaksızın , finallyblok her zaman çalışır . Ergo, nihayet bloğun içindeki ifadenin döndürdüğü değeri alırsın .returntryreturn

Bunu hem Ubuntu'da Firefox 3.6.10 hem de Chrome 6.0.472.63 ile test ettim. Bu kodun diğer tarayıcılarda farklı davranması mümkündür.


1

Nihayet bloğundan dönmek

Eğer finally-blok- bir değer döndürür, bu değer tüm dönüş değeri olur try-catch-finallyherhangi bakılmaksızın açıklamada returnifadelerden tryve catch-blocks

Referans: developer.mozilla.org


1

Burada biraz farklı bir cevap vereceğim: Evet, hem tryve hem de finallyblok çalıştırılır ve finallybir işlev için gerçek "dönüş" değerinden önceliklidir. Ancak, bu dönüş değerleri her zaman kodunuzda kullanılmaz.

İşte nedeni:

  • Aşağıdaki örnek res.send(), bir HTTP yanıtı oluşturan ve onu gönderen Express.js'yi kullanacaktır .
  • Sizin tryve finallybloğunuz bu işlevi şu şekilde yürütecektir:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

Bu kod, dizeyi trytarayıcınızda gösterecektir . AYRICA, örnek konsolunuzda bir hata gösterecektir. res.send()Fonksiyon denir iki kez . Bu, bir işlev olan her şeyde olur. Dene-yakala-nihayet bloğu bu gerçeği eğitimsiz bir göze gizleyecektir, çünkü (kişisel olarak) returndeğerleri sadece işlev kapsamlarıyla ilişkilendiriyorum .

Imho, en iyi bahsiniz asla returnbir finallyblok içinde kullanmamaktır . Kodunuzu aşırı karmaşık hale getirecek ve potansiyel olarak hataları maskeleyecektir.

Aslında, PHPStorm'da bunun için bir "Uyarı" veren varsayılan bir kod inceleme kuralı vardır:

https://www.jetbrains.com/help/phpstorm/javascript-and-typescript-return-inside-finally-block.html

Peki ne finallyiçin kullanıyorsun?

finallySadece eşyaları temizlemek için kullanırdım . Bir işlevin dönüş değeri için kritik olmayan herhangi bir şey.

Düşünürseniz mantıklı olabilir, çünkü altındaki bir kod satırına bağlı finallyolduğunuzda, tryveya içinde hatalar olabileceğini varsayarsınız catch. Ancak son 2, hata işlemenin gerçek yapı taşlarıdır. Sadece bir kullanmak returniçinde tryve catchonun yerine.


-2

Son olarak, HER ZAMAN bir try catch bloğunun sonunda çalıştırılması gerekir, böylece (spesifikasyona göre) bu nedenle yanlış döndürülür. Farklı tarayıcıların farklı uygulamalara sahip olmasının tamamen mümkün olduğunu unutmayın.


IE8, Firefox 3.6 ve Chrome 6: hepsi aynı;)
bonfo

-3

Peki buna ne dersin?

doubleReturn();

function doubleReturn() {
  let sex = 'boy';

  try {
    return sex;

    console.log('this never gets called...');
  } catch (e) {} finally {
    sex = 'girl'; 

    alert(sex);
  }
}
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.