Function nodes and `let` for variables

If I am not mistaken when you use variables you need to declare them at the start.

In the olden days it was:
var x = "foo";

This evolved into:
let x = "foo";

And so the question arises:
I am writing in a function node and I need multiple outputs.
msg1 and msg2
I'll supply screen shots only because they make what caught me more obvious:
And so I would expect to write the code as shown......
Note the error shown to me by the editor. (The small ~ under the . after msg2 and the let at the start - as per the line above. Which does NOT give an error.

And so I do this.

So why is it that it is accepting thelet on the first line and NOT on the second?

It doesn't trigger a syntax error, but it will not work like that if you try to send msg2, you will find its not defined.

So as you already know it should be in the format of let msg2= {reset:false}

Not really. You can define them when you need them.

No, both still exist. And you forgot const :slight_smile:

let and const define variables locally whereas var is always "hoisted" to the start of the program.

You need to remember that let and const are consttrained to the code block where they are defined. For example, if you define one inside the code block of an if statement, the variable only exists inside that block.


But this is not your issue. Your issue is that to assign a property to an object, you need to tell JavaScript that the variable IS an object. So you need a const msg2 = {} before assigning something to msg2.reset.

Or you can do it as suggested by smcgann99. :slight_smile:

(Bashes head against the brick wall)

Thanks.

I need to study let and var and const and get them clear in my mind to what they mean/do.

So (sorry: just wasted 3 hours writing code and it died miserably.)

Forgive the pathetic attempt to check this:

var x = "this is x";
if (x == "something")
{
      let y = "this is y";
      var z = "this is z";
      //  var `x` is/not? visible here?
}
//  Is `y` visible here?
//  Is `z` visible here?

Now to help me - I hope no end - could you confirm this theory?
inside the if{} part, can I have another x variable which is isolated from the something x defined outside the part.

This is sort of arcing back to when I did Arduino stuff. I never really got the hang of it either.
(Gotta start somewhere)

I'm guessing x will be visible within the if{} as it is declared outside that group/routine.
But I am not sure.
I seem to remember with the arduino code: subroutines did NOT see external variables UNLESS they were defined as GLOBAL.

I'll stop digging now.
The hole is big enough just now.

This how ChatGPT explains it...

In JavaScript, the scope of a variable refers to the accessibility of that variable within different parts of a program. There are three types of scope in JavaScript:

  1. Global scope: A variable declared outside a function or a block of code has a global scope, meaning it can be accessed from anywhere within the program.
  2. Local scope: A variable declared inside a function or a block of code has a local scope, meaning it can only be accessed within that function or block of code.
  3. Block scope: A variable declared with the let or const keywords inside a block of code, such as a loop or an if statement, has a block scope, meaning it can only be accessed within that block of code.

Variables declared with the var keyword have function scope, which means they are accessible within the function in which they are declared, as well as any nested functions. However, variables declared with let and const have block scope, which means they are only accessible within the block of code in which they are declared, including any nested blocks.

It's important to be aware of variable scope when writing JavaScript code to avoid unexpected behavior and potential bugs.

1 Like

Thanks Dave.

I fear I am not able to parse that to something I can use.

I get that Node-red uses JavaScript, and function nodes are a big way into that area.
But that's about the limit of my knowledge.

I don't use subroutines (well ok, maybe a couple of times, but they were extreme) and so a lot of what you just said is out of context. (Sorry)

I kind of have my head around the context levels in NR.

Global, flow and node.

Could you equate those names to those terms?

(My geuss/attempt)

Global = global.
Local = flow.
Block = node.

Ok, you added more after I started replying.

So you kind of did confirm what I just asked.

BUT

(sorry)

All of that is with var. Not let or the new kid const.
Where/how do the other two fit in that scheme?

Last minute thought:
const
That is sent ONCE in the code (per execution) and doesn't / can't change until the code is complete.
Yes?

The example code I posted would need to be "adjusted/edited" to make it work in Node-RED.
I didn't mean for it to be used - it was meant to be a visual example only.

EDIT:
I've removed the example code as I think it might cause confusion.

I get that is an example.

I am just trying to get a baseline which shows me an example from which I can build.

Oh, I just saw the edit pop up where you removed the example.
I thought it was pretty good..... But you say it may cause confsuion.
Now I am kind of more confused.

Sorry if it caused confusion (that was not intended) - I'll try to sort out a better example later.
In the meantime maybe another forum member might offer a readymade example.

Dave,

No it wasn't confusing. I just didn't understand it all.
It's my fault/problem.

I thought the example you posted (and deleted) was helpful. But maybe it is/was my stupidity that believed that and it wasn't. I can't say.

I am really just not getting the finer differences between those terms:
let var and const.

The key difference between var vs let and const, is that let and const are bound to a "scope" and var is not.

What is are example scopes:

{ }
function myFunction(){}

So if you define:

{
 var x = "hello"
}
console.log(x)  // < outside the scope, produces: hello

Try this again with let or const:

{
let a = "hello"
}
console.log(a) // < outside the scope, produces: Can't find variable a

So in short, vars can always be accessed while let and const are only accessible within their scope, which in turn can be global if you define outside and before the scope. Const should be considered as an immutable constant, like Pi. (although it is not true, but to not confuse you any further - assume they are immutable)

1 Like

So-o-o-o-o

Just to clarify I understand you correctly..

{
 var x = "hello"
}
console.log(x)  // < outside the scope, produces: hello

So if I go:

var x = "hello";
{
    //   x is visible here too - yes?
}

If I use var to define my variables I am forced to structure WHERE I define the variables.

Where as let makes all variables global.
(again) sorry. Just want to check.

So const is set at the line where it is set and from then on it can NOT be changed.

Am I getting it?

And I am probably (seeming) to repeat back to you what you just wrote.
By me doing this it sort of makes/helps it soak into the rocks in my head.

If I use var to define my variables I am forced to structure WHERE I define the variables.
Where as let makes all variables global .

No the other way around: let and const are scoped: in the scope they are declared, they can be used.

Currently the function node within node-red applies 'strict' typing, meaning if you don't define the variables it ends up in error.

Before strict, you were not required to declare variables and could immediately use:

x = "hello"

Which underwater implied: var x = "hello"

Now you are required to declare variables, you can still do that with var, but var is not scoped, meaning it can be hoisted, the term @TotallyInformation referred to: a variable can be used before it has been declared.

Rules of thumb:

  • declare variables at the top of the code. (be it in global or local (read: function) scope)
  • use const where ever you can.
  • don't use var.

Perhaps this article explains it better than i can.

I need to step back a bit and look at what you said.

As I read that l let controls from where in the code the variable can been seen.
Where as if I used var it doesn't seem to matter. (But I digress)

You used var in one and let in another.
Adding to my confusion you also changed the structure of the two examples.

I don't want to drag this on more than it needs to.
Yes, I could try it locally, but in case anyone else is stuck like me.

{
    var x = "hello";
}
console.log(x)   //  Will give "hello".

So what would happen in these examples:

One:

var x = "hello";
{
    //  Is x visible here?
}

Two:

{
     let x = "hello";
}
//  Is x visible here?

Lucky last:

let x = "hello";
{
    //  Is x visible here?
}

I don't know how to do what you showed as I don't have javascrpit installed - AFAIK.
And/or I don't know how to open a console.

UPDATE:

Ok, I made a bit of a flow and it does show me the subtle differences between var and let.

[{"id":"863368aec398661f","type":"debug","z":"aaa025a7d2bb5b14","name":"debug 73","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1080,"y":2390,"wires":[]},{"id":"37d5b43fd4c7dbc1","type":"inject","z":"aaa025a7d2bb5b14","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":720,"y":2390,"wires":[["24ee0b11388d213a"]]},{"id":"24ee0b11388d213a","type":"function","z":"aaa025a7d2bb5b14","name":"LET 2","func":"let y = 1;\nif (y == 1) {\n    let x = \"this is x\";\n}\nnode.warn(x);\nreturn msg;","outputs":1,"noerr":2,"initialize":"","finalize":"","libs":[],"x":870,"y":2390,"wires":[["863368aec398661f"]]},{"id":"16c28cb6e2408066","type":"function","z":"aaa025a7d2bb5b14","name":"VAR","func":"var x = \"this is x\";\nvar y = 1;\nif (y == 1) {\n    node.warn(x);\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":870,"y":2460,"wires":[["a2721de0f2033386"]]},{"id":"ea7f22d533827b5b","type":"inject","z":"aaa025a7d2bb5b14","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":720,"y":2460,"wires":[["16c28cb6e2408066"]]},{"id":"a2721de0f2033386","type":"debug","z":"aaa025a7d2bb5b14","name":"debug 74","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1080,"y":2460,"wires":[]},{"id":"8b794dc1920420fe","type":"function","z":"aaa025a7d2bb5b14","name":"VAR 2","func":"var y = 1;\nif (y == 1) {\n    var x = \"this is x\";\n}\nnode.warn(x);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":870,"y":2520,"wires":[["3c57e7a81925dc7a"]]},{"id":"5d1aa170893e0389","type":"inject","z":"aaa025a7d2bb5b14","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":720,"y":2520,"wires":[["8b794dc1920420fe"]]},{"id":"3c57e7a81925dc7a","type":"debug","z":"aaa025a7d2bb5b14","name":"debug 75","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1080,"y":2520,"wires":[]},{"id":"7d491892ce323b49","type":"function","z":"aaa025a7d2bb5b14","name":"LET","func":"let x = \"this is x\";\nlet y = 1;\nif (y == 1)\n{\n    node.warn(x);\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":870,"y":2320,"wires":[["c00e6fbf46ad97b4"]]},{"id":"6f74944952c5411f","type":"inject","z":"aaa025a7d2bb5b14","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":720,"y":2320,"wires":[["7d491892ce323b49"]]},{"id":"c00e6fbf46ad97b4","type":"debug","z":"aaa025a7d2bb5b14","name":"debug 76","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1080,"y":2320,"wires":[]}]

It seems to confirm what I thought.

let is better to make/force you to structure the code better.
If you want variables to be seen everywhere in the code, put them at the base of the code.
If you put them inside { }they are only visible within that{ }`.

You have it directly available in the browser. Right click on a page -> inspect element and then go to the console tab. You can enter javascript right there.

To answer your questions:
one: yes
two: no
lucky last: yes.

Note that if you use the browser console; use unique variable names, else you might be using/conflicting variables with unexpected outcomes.

1 Like

I am only wanting to get my head around the scope of let and var.

Seems I now know it.

Now const is/can only be set once per pass of the code.
But is it at the let or var scope?

Use const, unless you have to use let.
Only use var if you are maintaining old legacy code and it is already filled with lots of vars and you don't have time to do a complete refactor.

When using const, you will quickly be met with an error letting you know that you cannot redefine the value. In that case, switch to using let.

3 Likes

Thanks.

I am still not able to explain how I think how I see variables.

let or var are things that can be changed during the code's execution.

eg:

let x = msg.payload;
if (x == 10)
{
     x = x + 10;
}
msg.payload = x;
return msg;

Another way to write that would be - example:

const x = msg.payload;
let y = 0;
if (x == 10)
{
    y = x + 10;
}
msg.payload = y;
return msg;

Yes?

This is AN EXAMPLE of how to use const