Personally I like method 3 as it is easy to read and understand.
An alternative approach could be (out of curiosity):
Read the flow value inside your variable (in such case mv) and use this value in a function with default parameters.
Below code (inside a node function) will default the result to 5 (or whatever you hardcode) when mv is undefined (and only undefined).
function d5(d = 5) {
return d;
}
let mv = flow.get("myvar");
msg.payload = d5(mv); // or assign it back to variable mv
return msg;
Testing flow:
[{"id":"aaf6dea8.a6c82","type":"inject","z":"36592428.09b7ec","name":"","topic":"","payload":"9","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":96.0999984741211,"y":189.00000286102295,"wires":[["f02094c.004eb68"]]},{"id":"c6d44478.69cff8","type":"function","z":"36592428.09b7ec","name":"read myvar from and test myvar || 5","func":"function d5(d = 5) {\nreturn d;\n}\n\n\nlet mv = flow.get(\"myvar\");\n\nmsg.payload = d5(mv);\nreturn msg;","outputs":1,"noerr":0,"x":638.1000061035156,"y":217.00000190734863,"wires":[["d4dbec9c.0fea4"]]},{"id":"f02094c.004eb68","type":"function","z":"36592428.09b7ec","name":"Set myvar to msg.payload","func":"flow.set(\"myvar\",msg.payload);\n\nreturn msg;","outputs":1,"noerr":0,"x":319.1000061035156,"y":187.00000476837158,"wires":[["c6d44478.69cff8"]]},{"id":"1e9cf8a3.90e257","type":"inject","z":"36592428.09b7ec","name":"","topic":"","payload":"0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":97,"y":143,"wires":[["f02094c.004eb68"]]},{"id":"963c1ab9.359ac8","type":"function","z":"36592428.09b7ec","name":"Set myvar to undefined","func":"flow.set(\"myvar\",undefined);\n//node.warn(flow.get(\"myvar\"));\nreturn msg;","outputs":1,"noerr":0,"x":324,"y":260,"wires":[["c6d44478.69cff8"]]},{"id":"4d532d90.a50634","type":"inject","z":"36592428.09b7ec","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":114,"y":264,"wires":[["963c1ab9.359ac8"]]},{"id":"d4dbec9c.0fea4","type":"debug","z":"36592428.09b7ec","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":876.1000595092773,"y":217.00000381469727,"wires":[]}]
Just tested (really quick) so need better testing. It seems to be acceptable to convert a function with default parameters to an arrow function, making the code even shorter (but less readable).
let d5 = (d = 5) => d;
let mv = d5(flow.get("myvar"));
msg.payload = mv;
return msg;