Methods of variable sharing compared

In https://nodered.org/docs/writing-functions.html#flow-context it’s shown how to read context/flow/global shared variables (1).

var mv = flow.get('my_var')||0;

The || statement protects the failure in case the variable is not set yet. However, if default of non-0 required and the variable is not set yet, the proposed method is good for any value but 0. I.e. it’s impossible to pass zero with this statement:

var mv = flow.get('my_var')||5;

So far, I used brute-force try/catch (2):

try {
    var mv = flow.get('my_var');
} catch (err) {
    var mv = 5;
}

This is long and awkward. I spotted recently following method (3):

var mv = (flow.get('my_var') == undefined) ? 5 : flow.get('my_var');

IMHO, this is nicer, shorter and non-limiting method, unless tautology. :slight_smile:

My questions is:
What are possible disadvantages of method 3 versus methods 1 and 2? What do I miss?

Thank you.

I always use

var mv = flow.get('my_var');
if (typeof mv === 'undefined') mv = 5;

I’ve read somewhere that using typeof is the best way to test for undefined, whether the variable is declared or not, defined or not, zero, false, null etc. So as a rule I use this method.

I tend to use

var mv = flow.get('my_var');
if (mv === undefined) {
  mv = 5;
}

It is not quite as neat as yours but I think it is easier to understand and I assume is a little more efficient. I think it should be === though in practice it is unlikely to matter.
See undefined - JavaScript | MDN for the subtle difference if the value is ever null, which is not the same as undefined. It also explains there about the difference with using typeof to test undefined, which again is not quite the same.

Have a look here:
(https://groups.google.com/forum/#!searchin/node-red/cflurin|sort:date/node-red/h66MlN7kCMk/7zGdAUVDAwAJ)

Can you explain how that would work for the example with a default of 5 but 0 is a valid value?

Steve did explain it (0 is falsey value):

So yes, if your expected value could be interpreted as "falsey", you need to use the ternary operator and check for type undefined.
Examples of "falsey" values include: the empty string "", 0, NaN, boolean false (obviously), null and undefined
But these values are NOT considered "falsey": the strings "0" and "false", or an empty array!
--
Steve

@cflurin, Oh I see, I thought you had posted some code, but actually it was a link which explained what the problem is in the first place. So I didn’t understand what appeared to be javascript:

var reset = context.get(‘reset’) || true; > pitfall

Ok, I changed the link above.

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;

1 Like