11

In relation to: Java try-finally return design question

This doesn't quite answer my question also may not be relevant since it's java and not javascript: What is the order of execution in try,catch and finally

I understand that putting a return in a finally block will take precedence over a return in a catch block, however how does the sequence events work with the following code?

function confusion(){
  var test = "a";
  try{
    return test;
  }
  finally{
    test = "b";
  }
}

console.log("Result", confusion()); //"a"

My general understanding of returning of anything is that control usually returns to the context of where the method is being called, so the fact that execution continues is kind've confusing to me.

In this scenario I thought it might play out something like:

-Function set to return test -> finally changes value of test -> test is returned with updated value.

But instead it seems like some sort've state is held for the try block and finally misses the timing?

Community
  • 1
  • 1
camjocotem
  • 375
  • 5
  • 18
  • 6
    The value of `test` gets resolved when you `return` it in the `try` block. It stores the value, not the identifier. Subsequent rebinding of the identifier to another value doesn't change what's referenced to be returned. – jonrsharpe Apr 23 '17 at 13:06
  • 4
    It would be different if `test` was an object and you were updating a property, like `var test = {foo: "a"}`. So then when you return `test` and do `test.foo = "b"` in the `finally` block, the caller will see the mutation. –  Apr 23 '17 at 13:09
  • I've added a live example below to demonstrate what @user1106925 said. – Mr.Z Feb 17 '22 at 08:47

2 Answers2

15

When you return out of a try or catch block with an associated finally block, execution enters the finally block because that's the purpose of it: To handle common completion actions for the try/catch.

In your code, what happens as of the return is:

  1. The value of test is read from the variable and set aside for use later.

  2. Control passes to finally.

  3. Code in finally changes the value of the variable test (which has no effect on the value that was set aside in #1).

  4. When the end of the finally block is encountered, the function returns, using the value set aside in #1 as its return value.

This is covered in The try Statement / Runtime Semantics: Evaluation in the specification, and perhaps more readably in try...catch on MDN under "The finally clause."

Note that the finally can interrupt the return process, by either throwing an exception, or returning a new value. If it does either of those things, it wins over the return in the try (or catch).


Side Note re your linked Java question: JavaScript's try/catch/finally works just like Java's except: 1. You can only have one catch block because exceptions aren't typed, and 2. JavaScript doesn't have Java's try-with-resources statement.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • TJ, I just had a look at [here](https://www.ecma-international.org/ecma-262/5.1/#sec-12.9) for more information. I didn't find any. Can you link me to a link which gives an elaborate explanation of what you said. – Rajaprabhu Aravindasamy Apr 23 '17 at 13:12
  • @RajaprabhuAravindasamy: The 5.1 spec has been out of date for nearly two years. :-) I've added a link to the relevant part of the ES2016 spec (which will be obsoleted by the ES2017 spec in June). – T.J. Crowder Apr 23 '17 at 13:16
0

Demonstrating a comment made by @user1106925 that using a Javascript object instead of a primitive produces OP's expected behavior.

function lessConfusion(){
  var result = {test: "a"};
  try{
    return result;
  }
  finally{
    result.test = "b";
  }
}

console.log("result", lessConfusion()); //result.test="b"
Mr.Z
  • 542
  • 2
  • 5
  • 18