Mengapa pengembalian dalam `akhirnya` menggantikan` coba`?

100

Bagaimana cara kerja pernyataan pengembalian di dalam blok coba / tangkap?

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

Saya mengharapkan keluaran dari fungsi ini true, tetapi sebaliknya false!

bonfo
sumber
Untuk orang lain, lakukan pengembalian salah di blok penangkap, bukan akhirnya.
habibhassani

Jawaban:

95

Akhirnya selalu dijalankan. Untuk itulah, yang berarti pengembaliannya digunakan dalam kasus Anda.

Anda akan ingin mengubah kode Anda menjadi seperti ini:

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

Secara umum Anda tidak pernah ingin memiliki lebih dari satu pernyataan pengembalian dalam suatu fungsi, hal-hal seperti inilah alasannya.

annakata
sumber
47
Saya berpendapat memiliki lebih dari satu pernyataan pengembalian tidak selalu buruk - Lihat stackoverflow.com/questions/36707/… untuk diskusi lebih lanjut.
Castrohenge
5
Saya juga tidak setuju tentang aturan satu kali pengembalian. Anda tidak boleh kembali dari akhirnya, meskipun (di C #, itu bahkan tidak diperbolehkan).
erikkallen
@erikkallen - itu poin yang bagus. Pengembalian di luar blok TCF akan menjadi yang terbaik tetapi kode contoh akan sedikit dipaksakan :)
annakata
1
@Castrohenge - ini bukan aturan yang keras dan cepat, tetapi sebagian besar contoh copunter di utas itu dibuat-buat, dan satu-satunya kasus valid yang saya lihat adalah "klausa penjaga" (pada dasarnya pola pemeriksaan data masukan di bagian atas fungsi dan kembali secara kondisional). Itu kasus yang benar-benar valid, tetapi sebenarnya pengembalian itu harus menjadi pengecualian (sekali lagi tidak sulit dan cepat).
annakata
1
Sebenarnya di IE6 dan IE7, akhirnya tidak selalu dijalankan di semua kasus karena bug browser yang cukup serius. Secara khusus - jika pengecualian dilemparkan ke blok coba-akhirnya yang tidak dikelilingi oleh uji coba tingkat yang lebih tinggi, blok akhirnya tidak akan dijalankan. Berikut adalah kasus uji jsfiddle.net/niallsmart/aFjKq . Masalah ini telah diperbaiki di IE8.
Niall Smart
44

Menurut ECMA-262 (5ed, Desember 2009), di hlm.96:

Produksi TryStatement : try Block Finallydievaluasi sebagai berikut:

  1. Misalkan B adalah hasil evaluasi Blok.
  2. Misalkan F adalah hasil evaluasi Akhirnya.
  3. Jika tipe F. normal, kembalikan B.
  4. Kembali F.

Dan dari hal.36:

Jenis Penyelesaian digunakan untuk menjelaskan perilaku pernyataan ( break, continue, returndan throw) yang melakukan transfer nonlokal kontrol. Nilai-nilai dari jenis Penyelesaian adalah tiga kali lipat dari bentuk (jenis, nilai, target) , di mana jenis adalah salah satu dari normal, break, continue, return, atau throw, nilai adalah nilai apapun bahasa ECMAScript atau kosong, dan sasaran adalah setiap identifier ECMAScript atau kosong.

Sudah jelas bahwa return falseakan menetapkan jenis penyelesaian akhirnya sebagai pengembalian , yang menyebabkan try ... finallyharus dilakukan 4. Kembali F .

livibetter
sumber
2
Setelah membaca semua jenis jawaban yang "pada dasarnya benar tetapi agak licin dan tidak mengklarifikasi" untuk pertanyaan ini, yang satu ini sebenarnya masuk akal. Bit kuncinya adalah bahwa apa pun yang "terjadi" di akhir percobaan + tangkapan (kembali atau lempar atau hanya aliran normal) akan diingat saat menjalankan bagian terakhir dan kemudian benar-benar terjadi hanya jika tidak ada yang terjadi di akhir akhirnya.
PreventRage
14

Saat Anda menggunakan finally, kode apa pun di dalam blok itu diaktifkan sebelum metode keluar. Karena Anda menggunakan pengembalian di finallyblok, itu memanggil return falsedan menimpa yang sebelumnya return truedi tryblok.

(Terminologi mungkin kurang tepat.)

djdd87.dll
sumber
4

Penulisan ulang blok terakhir coba blokir kembali (secara kiasan).

Hanya ingin menunjukkan, bahwa jika Anda mengembalikan sesuatu dari akhirnya, maka itu akan dikembalikan dari fungsinya. Tetapi jika pada akhirnya tidak ada kata 'kembali' - itu akan dikembalikan nilai dari blok percobaan;

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

Jadi-akhirnya- returnmenulis ulang kembalinya -try- return.

Mihey Mik
sumber
3

mengapa Anda mendapatkan kesalahan adalah Anda dikembalikan dalam blok terakhir. akhirnya blok harus selalu dijalankan. jadi return trueperubahanmu menjadireturn false

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

Sejauh yang saya tahu, finallyblok selalu dijalankan, terlepas dari apakah Anda memiliki returnpernyataan di dalamnya tryatau tidak. Ergo, Anda mendapatkan nilai yang dikembalikan oleh returnpernyataan di dalam blok akhirnya.

Saya menguji ini dengan Firefox 3.6.10 dan Chrome 6.0.472.63 keduanya di Ubuntu. Kode ini mungkin berlaku berbeda di browser lain.

Manoj Govindan
sumber
1

Kembali dari blok terakhir

Jika finally-block mengembalikan nilai, nilai ini menjadi nilai kembali dari seluruh try-catch-finallypernyataan, terlepas dari returnpernyataan apa pun di trydan catch-blocks

Referensi: developer.mozilla.org

Tho
sumber
1

Saya akan memberikan jawaban yang sedikit berbeda di sini: Ya, blok trydan finallydieksekusi, dan finallylebih diutamakan daripada nilai "pengembalian" sebenarnya untuk suatu fungsi. Namun, nilai kembali ini tidak selalu digunakan dalam kode Anda.

Inilah alasannya:

  • Contoh di bawah ini akan menggunakan res.send()dari Express.js, yang membuat respons HTTP dan mengirimkannya.
  • Anda trydan finallyblok keduanya akan menjalankan fungsi ini seperti:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

Kode ini akan menampilkan string trydi browser Anda. JUGA, contoh akan menunjukkan kesalahan di konsol Anda. The res.send()fungsi disebut dua kali . Ini akan terjadi dengan apa pun yang merupakan fungsi. Blok coba-tangkap-akhirnya akan mengaburkan fakta ini ke mata yang tidak terlatih, karena (secara pribadi) saya hanya mengaitkan returnnilai dengan lingkup fungsi.

Taruhan terbaik Anda adalah tidak pernah menggunakan returndi dalam finallyblok . Ini akan memperumit kode Anda dan berpotensi menutupi kesalahan.

Faktanya, ada pengaturan aturan inspeksi kode default di PHPStorm yang memberikan "Peringatan" untuk ini:

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

Jadi apa yang kamu gunakan finally ?

Saya akan menggunakan finally hanya untuk membersihkan barang-barang. Apa pun yang tidak penting untuk nilai kembalian suatu fungsi.

Mungkin masuk akal jika Anda memikirkannya, karena saat Anda bergantung pada baris kode di bawah finally, Anda berasumsi bahwa mungkin ada kesalahan dalam tryatau catch. Tapi 2 yang terakhir itu adalah blok bangunan penanganan error yang sebenarnya. Cukup gunakan returndalam trydan catchsebagai gantinya.

Api
sumber
-2

Akhirnya diharapkan SELALU berjalan di akhir blok coba tangkap sehingga (menurut spesifikasi) adalah mengapa Anda mendapatkan kesalahan kembali. Perlu diingat bahwa sangat mungkin browser yang berbeda memiliki implementasi yang berbeda.

Darko Z
sumber
IE8, Firefox 3.6 dan Chrome 6: semua sama;)
bonfo
-3

Bagaimana dengan ini?

doubleReturn();

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

  try {
    return sex;

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

    alert(sex);
  }
}
Thomas Karlsson
sumber