Чому повернення у "нарешті" замінює "спробу"?


94

Як працює оператор return у блоці try / catch?

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

Я очікую, що результат цієї функції буде true, але натомість він є false!


Для інших робіть return false у блоці catch, а не остаточно.
habibhassani

Відповіді:


91

Нарешті завжди виконує. Ось для чого він призначений, а це означає, що у вашому випадку використовується повернення.

Ви захочете змінити свій код, щоб він був приблизно таким:

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

Взагалі кажучи, ви ніколи не хочете, щоб у функції було більше одного оператора return, подібні речі - ось чому.


45
Я б стверджував, що наявність декількох операторів повернення не завжди погано - див. Stackoverflow.com/questions/36707/…, щоб отримати додаткові обговорення.
Кастрогенге

5
Я теж не згоден з правилом єдиного повернення. Вам ніколи не слід повертатися з нарешті, хоча (у C # це навіть не дозволяється).
erikkallen

@erikkallen - це хороший момент. Повернення поза блоком TCF було б найкращим, але приклад коду був би трохи вимушеним :)
annakata

1
@Castrohenge - це не жорстке правило, але більшість прикладів copunter у цій темі є досить надуманими, і єдиним дійсним випадком, який я бачу, є "клаузула охорони" (по суті, шаблон перевірки вхідних даних у верхній частині функція та повернення умовно). Це цілком дійсний випадок, але насправді ці повернення повинні бути винятками (знову ж таки не важкими та швидкими).
annakata

1
Насправді в IE6 та IE7 нарешті не завжди виконується у всіх випадках через досить серйозну помилку браузера. Зокрема - якщо виняток викидається в блок try-нарешті, який не оточений спробою-лову вищого рівня, тоді блок нарешті не буде виконуватися. Ось тестовий приклад jsfiddle.net/niallsmart/aFjKq . Ця проблема була виправлена ​​в IE8.
Niall Smart

43

Відповідно до ECMA-262 (5ed, грудень 2009 р.), В с. 96:

Виробництво TryStatement : try Block Finallyоцінюється наступним чином:

  1. Нехай B є результатом оцінки Block.
  2. Нехай F є результатом оцінки Нарешті.
  3. Якщо тип F. нормальний, поверніть B.
  4. Повернення Ф.

І зі стор. 36:

Тип Завершення використовується для пояснення поведінки операторів ( break, continue, returnі throw) , які виконують нелокальних передачу управління. Значення типу завершення є триплети виду (тип, значення, мета) , де тип є одним з normal, break, continue, return, або throw, значення будь-яке значення ECMAScript мови або порожній, і цільової будь ідентифікатор ECMAScript або порожній.

Очевидно , що return falseб встановити тип завершення в кінці кінців , як повернення , що викликає try ... finallyробити 4. Повернення F .


2
Прочитавши всілякі відповіді на це запитання "в основному правильні, але якимось мінливими та нез'ясовуючими", насправді це мало сенс. Ключовим моментом було те, що все, що "трапляється" в кінці try + catch (повернення чи кидок або просто звичайний потік), запам'ятовується під час запуску останньої частини, а потім насправді відбувається лише в тому випадку, якщо нічого не відбувається в кінці нарешті.
PreventRage

14

Коли ви використовуєте finally, будь-який код у цьому блоці запускається до виходу методу. Оскільки ви використовуєте повернення в finallyблоці, воно викликає return falseта замінює попереднє return trueв tryблоці.

(Термінологія може бути не зовсім правильною.)


3

чому ви отримуєте false - це повернення в остаточному блоці. нарешті блок повинен виконуватися завжди. так що ваші return trueзміни доreturn false

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

3

Нарешті блок переписує спробу повернення блоку (образно кажучи).

Просто хотів зазначити, що якщо ви повернете щось із, нарешті, це буде повернуто з функції. Але якщо нарешті немає слова "return" - йому буде повернуто значення з блоку try;

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

Отже-нарешті- returnпереписує повернення -спробо- return.


1

Наскільки мені відомо, finallyблок завжди виконується, незалежно від того, є у вас returnзаява всередині tryчи ні. Ерго, ви отримуєте значення, яке повертається returnоператором всередині блоку нарешті.

Я протестував це за допомогою Firefox 3.6.10 та Chrome 6.0.472.63, обидва в Ubuntu. Можливо, цей код може поводитися по-різному в інших браузерах.


1

Тут я дам трохи іншу відповідь: так, tryі finallyблок, і блок виконуються, і finallyмає перевагу над фактичним значенням "return" для функції. Однак ці повернені значення не завжди використовуються у вашому коді.

Ось чому:

  • У наведеному нижче прикладі буде використано res.send()Express.js, який створює відповідь HTTP і відправляє її.
  • І ваш, tryі finallyблок будуть виконувати цю функцію так:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

Цей код покаже рядок tryу вашому браузері. ТАКОЖ, приклад покаже помилку у вашій консолі. res.send()Функція викликається двічі . Це відбуватиметься з усім, що є функцією. Блок try-catch-нарешті затуманить цей факт для нетренованого ока, оскільки (особисто) я пов'язую лише returnзначення з сферами функцій.

Імхо, ваша найкраща ставка - ніколи не використовувати returnвсередині finallyблоку . Це призведе до ускладнення вашого коду та потенційно замаскує помилки.

Насправді у PHPStorm встановлено правило перевірки коду за замовчуванням, яке дає "Попередження" про це:

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

То для чого ти використовуєш finally?

Я б використовував finallyлише для прибирання речей. Все, що не є критичним для поверненого значення функції.

Це може мати сенс, якщо ви задумаєтесь, тому що коли ви залежате від рядка коду finally, ви припускаєте, що в tryабо можуть бути помилки catch. Але ці останні 2 - це фактичні будівельні блоки обробки помилок. Просто використовуйте returnin tryі catchзамість цього.


0

Повернення з блоку нарешті

Якщо finally-block повертає значення, це значення стає повертаним значенням усього try-catch-finallyоператора, незалежно від будь-яких returnоператорів у tryта catch-blocks

Довідково: developer.mozilla.org


-2

Нарешті передбачається ЗАВЖДИ виконуватися в кінці блоку try catch так, що (за специфікацією) саме тому ви повертаєте false. Майте на увазі, що цілком можливо, що різні браузери мають різну реалізацію.


IE8, Firefox 3.6 та Chrome 6: все однаково;)
bonfo

-3

Як що до цього?

doubleReturn();

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

  try {
    return sex;

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

    alert(sex);
  }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.