เหตุใดผลตอบแทนใน "ในที่สุด" จึงแทนที่ "ลอง"


100

คำสั่งส่งคืนภายในบล็อก try / catch ทำงานอย่างไร

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

ฉันคาดหวังว่าผลลัพธ์ของฟังก์ชันนี้จะเป็นtrueแต่มันกลับเป็นfalse!


สำหรับคนอื่น ๆ ให้ส่งคืนเท็จในบล็อก catch ไม่ใช่ในที่สุด
habibhassani

คำตอบ:


95

สุดท้ายมักจะดำเนินการ นั่นคือสิ่งที่มีไว้สำหรับซึ่งหมายความว่าผลตอบแทนจะถูกใช้ในกรณีของคุณ

คุณจะต้องเปลี่ยนรหัสของคุณเพื่อให้เป็นแบบนี้:

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

โดยทั่วไปคุณไม่ต้องการมีคำสั่ง return มากกว่าหนึ่งคำสั่งในฟังก์ชันสิ่งนี้จึงเป็นสาเหตุ


47
ฉันจะเถียงว่าการมีคำสั่งส่งคืนมากกว่าหนึ่งคำไม่ได้แย่เสมอไป - ดูstackoverflow.com/questions/36707/…สำหรับการสนทนาเพิ่มเติม
Castrohenge

5
ฉันไม่เห็นด้วยเกี่ยวกับกฎผลตอบแทนเดียว คุณไม่ควรกลับมาในที่สุดแม้ว่า (ใน C # จะไม่ได้รับอนุญาตด้วยซ้ำ)
erikkallen

@erikkallen - นั่นเป็นจุดที่ดี การส่งคืนนอกบล็อก TCF จะดีที่สุด แต่โค้ดตัวอย่างจะบังคับนิดหน่อย :)
annakata

1
@ คาสโตรเฮนจ์ - ไม่ใช่กฎที่ยากและรวดเร็ว แต่ตัวอย่างส่วนใหญ่ของผู้ร่วมงานในเธรดนั้นได้รับการออกแบบมาค่อนข้างดีและกรณีเดียวที่ฉันเห็นคือ "guard clause" (โดยพื้นฐานแล้วรูปแบบการตรวจสอบข้อมูลอินพุตที่ด้านบนของ ฟังก์ชันและส่งคืนตามเงื่อนไข) นั่นเป็นกรณีที่ถูกต้องอย่างสมบูรณ์ แต่ผลตอบแทนเหล่านั้นควรเป็นข้อยกเว้น (อีกครั้งไม่ใช่อย่างหนักและรวดเร็ว)
annakata

1
จริงๆแล้วใน IE6 และ IE7 ในที่สุดก็ไม่ได้ดำเนินการในทุกกรณีเนื่องจากข้อผิดพลาดของเบราว์เซอร์ที่ค่อนข้างร้ายแรง โดยเฉพาะอย่างยิ่ง - หากเกิดข้อยกเว้นในบล็อกการลองสุดท้ายที่ไม่ได้ล้อมรอบด้วยการลองจับระดับที่สูงกว่าการบล็อกจะไม่ดำเนินการในที่สุด นี่คือกรณีทดสอบjsfiddle.net/niallsmart/aFjKq ปัญหานี้ได้รับการแก้ไขแล้วใน IE8
Niall Smart

44

อ้างอิงจาก ECMA-262 (5ed ธันวาคม 2009) ในหน้า 96:

การผลิตTryStatement : try Block Finallyได้รับการประเมินดังนี้:

  1. ให้ B เป็นผลลัพธ์ของการประเมิน Block
  2. ให้ F เป็นผลลัพธ์ของการประเมินในที่สุด
  3. ถ้าประเภท F. เป็นปกติให้ส่งคืน B
  4. กลับ F.

และจากหน้า 36:

ประเภทแล้วเสร็จจะใช้ในการอธิบายพฤติกรรมของงบ ( break, continue, returnและthrow) ที่ดำเนินการถ่ายโอนต่างแดนของการควบคุม ค่าของชนิดเสร็จเป็นอเนกประสงค์ของรูปแบบ(ชนิดค่าเป้าหมาย)ที่ประเภทเป็นหนึ่งnormal, break, continue, returnหรือthrow, ค่าใดค่าภาษา ECMAScript หรือเปล่าและเป้าหมายใด ๆ ที่ระบุ ECMAScript หรือเปล่า

เป็นที่ชัดเจนว่าreturn falseจะกำหนดชนิดของความสำเร็จของในที่สุดก็เป็นผลตอบแทนที่ทำให้เกิดtry ... finallyจะทำอย่างไร4. กลับ F


2
หลังจากอ่านคำตอบที่ "ถูกต้องโดยทั่วไป แต่ไม่ชัดเจนและไม่กระจ่าง" ทุกประเภทสำหรับคำถามนี้คำถามนี้ก็สมเหตุสมผล บิตสำคัญคือไม่ว่าอะไรก็ตามที่ "เกิดขึ้น" ในตอนท้ายของการลอง + จับ (กลับหรือโยนหรือเพียงแค่การไหลปกติ) จะถูกจดจำในขณะที่มันทำงานในส่วนสุดท้ายและจะเกิดขึ้นจริงก็ต่อเมื่อไม่มีอะไรเกิดขึ้นในตอนท้ายของที่สุด
PreventRage

14

เมื่อคุณใช้finallyรหัสใด ๆ ในบล็อกนั้นจะเริ่มทำงานก่อนที่เมธอดจะออก เนื่องจากคุณกำลังใช้ผลตอบแทนในfinallyบล็อกจึงเรียกreturn falseและลบล้างค่าก่อนหน้าreturn trueในtryบล็อก

(คำศัพท์อาจไม่ถูกต้องนัก)


4

การเขียนบล็อกใหม่ในที่สุดลองบล็อกการส่งคืน (พูดเปรียบเปรย)

แค่อยากจะชี้ให้เห็นว่าถ้าคุณส่งคืนบางสิ่งจากในที่สุดมันจะถูกส่งคืนจากฟังก์ชัน แต่ถ้าในที่สุดไม่มีคำว่า 'return' มันจะถูกส่งกลับค่าจาก try block;

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

ดังนั้น -finally- returnปรับเปลี่ยนการกลับมาของ return-try-


3

ทำไมคุณถึงได้รับเท็จคุณกลับมาในที่สุด สุดท้ายบล็อกควรรันเสมอ ดังนั้นreturn trueการเปลี่ยนแปลงของคุณเป็นreturn false

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

1

เท่าที่ฉันรู้finallyบล็อกจะดำเนินการเสมอไม่ว่าคุณจะมีreturnคำสั่งภายในtryหรือไม่ก็ตาม Ergo คุณจะได้รับค่าที่ส่งคืนโดยreturnคำสั่งภายในบล็อกในที่สุด

ฉันทดสอบกับ Firefox 3.6.10 และ Chrome 6.0.472.63 ทั้งใน Ubuntu เป็นไปได้ว่าโค้ดนี้อาจทำงานแตกต่างจากเบราว์เซอร์อื่น


1

กลับมาจากบล็อกสุดท้าย

ถ้าfinally-block ส่งคืนค่าค่านี้จะกลายเป็นค่าส่งคืนของtry-catch-finallyคำสั่งทั้งหมดโดยไม่คำนึงถึงreturnคำสั่งใด ๆ ในtryและcatch-blocks

ข้อมูลอ้างอิง: developer.mozilla.org


1

ฉันจะให้คำตอบที่แตกต่างออกไปเล็กน้อยที่นี่: ใช่ทั้ง the tryและfinallyblock ถูกเรียก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ค่ากับขอบเขตของฟังก์ชันเท่านั้น

imho ทางออกที่ดีที่สุดของคุณคือการไม่เคยใช้returnภายในfinallyบล็อก จะทำให้โค้ดของคุณซับซ้อนเกินไปและอาจปกปิดข้อผิดพลาด

ในความเป็นจริงมีการตั้งค่ากฎการตรวจสอบโค้ดเริ่มต้นใน PHPStorm ที่ให้ "คำเตือน" สำหรับสิ่งนี้:

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

แล้วคุณใช้finallyทำอะไร?

ฉันจะใช้finallyเพื่อล้างสิ่งต่างๆเท่านั้น สิ่งใดก็ตามที่ไม่สำคัญสำหรับค่าที่ส่งคืนของฟังก์ชัน

มันอาจจะทำให้รู้สึกว่าคุณคิดเกี่ยวกับเรื่องนี้เพราะเมื่อคุณขึ้นอยู่กับบรรทัดของรหัสภายใต้finallyคุณจะสมมติว่าอาจจะมีข้อผิดพลาดในหรือtry catchแต่ 2 รายการสุดท้ายเป็นส่วนประกอบสำคัญของการจัดการข้อผิดพลาด เพียงแค่ใช้returnในtryและcatchแทน


-2

สุดท้ายควรจะรันทุกครั้งที่ส่วนท้ายของ try catch block ดังนั้น (ตามข้อกำหนด) จึงเป็นสาเหตุที่คุณได้รับการส่งคืนเท็จ โปรดทราบว่าเป็นไปได้ทั้งหมดที่เบราว์เซอร์ที่แตกต่างกันจะมีการใช้งานที่แตกต่างกัน


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);
  }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.