Tại sao trả về trong `cuối cùng` ghi đè` thử`?


94

Câu lệnh return bên trong khối try / catch hoạt động như thế nào?

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

Tôi mong đợi kết quả đầu ra của hàm này là true, nhưng thay vào đó là false!


Đối với những người khác, trả về false trong khối bắt chứ không phải cuối cùng.
habibhassani

Câu trả lời:


91

Cuối cùng luôn luôn thực thi. Đó là những gì nó để, có nghĩa là nó trở lại được sử dụng trong trường hợp của bạn.

Bạn sẽ muốn thay đổi mã của mình để nó giống như sau:

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

Nói chung, bạn không bao giờ muốn có nhiều hơn một câu lệnh trả về trong một hàm, những thứ như thế này là lý do tại sao.


45
Tôi cho rằng việc có nhiều hơn một câu lệnh trả về không phải lúc nào cũng xấu - Hãy xem stackoverflow.com/questions/36707/… để thảo luận thêm.
Castrohenge

5
Tôi cũng không đồng ý về quy tắc một trả lại. Tuy nhiên, bạn không bao giờ nên quay trở lại từ cuối cùng (trong C #, nó thậm chí không được phép).
erikkallen

@erikkallen - đó là một điểm tốt. Một sự trở về bên ngoài khối TCF sẽ là tốt nhất nhưng mã ví dụ sẽ được một chút buộc :)
annakata

1
@Castrohenge - nó không phải là một quy tắc khó và nhanh, nhưng hầu hết các ví dụ về copunter trong chuỗi đó đều khá phức tạp và trường hợp hợp lệ duy nhất tôi thấy là "mệnh đề bảo vệ" (về cơ bản là mẫu kiểm tra dữ liệu đầu vào ở đầu hàm và trả về có điều kiện). Đó là một trường hợp hoàn toàn hợp lệ, nhưng thực sự những lợi nhuận đó phải là ngoại lệ (một lần nữa không khó và nhanh).
annakata

1
Trên thực tế, trong IE6 và IE7, cuối cùng không phải lúc nào cũng thực thi trong mọi trường hợp do một lỗi trình duyệt khá nghiêm trọng. Cụ thể - nếu một ngoại lệ được ném vào một khối try-final không được bao quanh bởi một khối try-catch cấp cao hơn, thì khối cuối cùng sẽ không thực thi. Đây là trường hợp thử nghiệm jsfiddle.net/niallsmart/aFjKq . Sự cố này đã được khắc phục trong IE8.
Niall Smart

43

Theo ECMA-262 (5ed, tháng 12 năm 2009), trong trang 96:

Việc sản xuất TryStatement : try Block Finallyđược đánh giá như sau:

  1. Gọi B là kết quả đánh giá Block.
  2. Gọi F là kết quả đánh giá Cuối cùng.
  3. Nếu F.type là bình thường, trả về B.
  4. Trả lại F.

Và từ trang 36:

Các loại Hoàn thành được sử dụng để giải thích hành vi của báo cáo ( break, continue, returnthrow) mà thực hiện chuyển không cục bộ tầm kiểm soát. Giá trị của các loại Hoàn là gấp ba trong những hình thức (loại, giá trị, mục tiêu) , nơi loại là một trong những normal, break, continue, return, hay throw, giá trị là bất kỳ giá trị ngôn ngữ ECMAScript hoặc trống rỗng, và mục tiêu là bất kỳ định danh ECMAScript đúng hoặc bỏ trống.

Rõ ràng là return falsesẽ thiết lập kiểu kết thúc cuối cùnglợi nhuận , mà gây ra try ... finallylàm 4. Trở F .


2
Sau khi đọc tất cả các loại câu trả lời "về cơ bản là đúng nhưng bằng cách nào đó khó hiểu và không rõ ràng" cho câu hỏi này, câu trả lời này thực sự có ý nghĩa. Điểm mấu chốt là bất cứ điều gì "xảy ra" ở cuối lần thử + bắt (quay lại hoặc ném hoặc chỉ là luồng bình thường) đều được ghi nhớ khi nó chạy phần cuối cùng và sau đó thực sự chỉ xảy ra nếu không có gì xảy ra vào cuối cuối cùng.
PreventRage

14

Khi bạn sử dụng finally, bất kỳ mã nào trong khối đó sẽ kích hoạt trước khi phương thức thoát. Bởi vì bạn đang sử dụng trả về trong finallykhối, nó sẽ gọi return falsevà ghi đè phần trước return truetrong trykhối.

(Thuật ngữ có thể không đúng.)


3

tại sao bạn nhận được sai là bạn được trả về trong một khối cuối cùng. cuối cùng khối nên thực thi luôn. vì vậy bạn return truethay đổi thànhreturn false

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

3

Khối cuối cùng được viết lại thử khối trả về (nói theo nghĩa bóng).

Chỉ muốn chỉ ra rằng nếu bạn trả về một cái gì đó từ cuối cùng, thì nó sẽ được trả về từ hàm. Nhưng nếu cuối cùng không có từ 'return' - nó sẽ được trả về giá trị từ khối try;

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

Vì vậy, -finally- returnviết lại sự trở lại của -try- return.


1

Theo như tôi biết, finallykhối này luôn thực thi, bất kể bạn có returncâu lệnh bên trong tryhay không. Ergo, bạn nhận được giá trị được trả về bởi returncâu lệnh bên trong khối cuối cùng.

Tôi đã thử nghiệm điều này với Firefox 3.6.10 và Chrome 6.0.472.63 cả trong Ubuntu. Có thể mã này có thể hoạt động khác trong các trình duyệt khác.


1

Tôi sẽ đưa ra một câu trả lời hơi khác ở đây: Có, cả khối tryfinallykhối đều được thực thi và finallyđược ưu tiên hơn giá trị "trả về" thực tế cho một hàm. Tuy nhiên, những giá trị trả về này không phải lúc nào cũng được sử dụng trong mã của bạn.

Đây là lý do tại sao:

  • Ví dụ dưới đây sẽ sử dụng res.send()từ Express.js, tạo một phản hồi HTTP và gửi nó đi.
  • Khối của bạn tryfinallykhối sẽ thực thi chức năng này như sau:
try {
    // Get DB records etc.
    return res.send('try');
} catch(e) {
    // log errors
} finally {
    return res.send('finally');
}

Mã này sẽ hiển thị chuỗi trytrong trình duyệt của bạn. CŨNG CÓ, ví dụ sẽ hiển thị lỗi trong bảng điều khiển của bạn. Các res.send()chức năng được gọi là hai lần . Điều này sẽ xảy ra với bất kỳ thứ gì là một hàm. Khối try-catch-final sẽ làm xáo trộn thực tế này với con mắt chưa được đào tạo, bởi vì (cá nhân tôi) tôi chỉ liên kết returncác giá trị với phạm vi chức năng.

Đặt cược tốt nhất của bạn là không bao giờ sử dụng returnbên trong một finallykhối . Nó sẽ làm phức tạp mã của bạn và có khả năng che dấu lỗi.

Trên thực tế, có một quy tắc kiểm tra mã mặc định được thiết lập trong PHPStorm đưa ra "Cảnh báo" cho điều này:

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

Vậy bạn dùng finallyđể làm gì?

Tôi sẽ finallychỉ sử dụng để dọn dẹp những thứ. Bất kỳ thứ gì không quan trọng đối với giá trị trả về của một hàm.

Nó có thể có ý nghĩa nếu bạn nghĩ về nó, bởi vì khi bạn phụ thuộc vào một dòng mã bên dưới finally, bạn đang giả định rằng có thể có lỗi trong tryhoặc catch. Nhưng 2 cuối cùng là khối xây dựng thực tế của việc xử lý lỗi. Chỉ cần sử dụng một returntrong trycatchthay thế.


0

Trở về từ khối cuối cùng

Nếu finally-block trả về một giá trị, giá trị này sẽ trở thành giá trị trả về của toàn bộ try-catch-finallycâu lệnh, bất kể bất kỳ returncâu lệnh nào trong trycatch-block

Tham khảo: developer.mozilla.org


-2

Cuối cùng được cho là LUÔN LUÔN chạy ở cuối khối try catch để (theo đặc điểm kỹ thuật) là lý do tại sao bạn nhận được trả về false. Hãy nhớ rằng hoàn toàn có thể xảy ra trường hợp các trình duyệt khác nhau có các cách triển khai khác nhau.


IE8, Firefox 3.6 và Chrome 6: tất cả đều giống nhau;)
bonfo

-3

Cái này thì sao?

doubleReturn();

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

  try {
    return sex;

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

    alert(sex);
  }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.