Global.put not needed as variable altered by reference?

Hi
From a general engineering background and writing a lot of functions in node red and learning as I go.
I am very familar with C etc but finding JS a bit obscure at times and would appreciate some help.

I understand about javscript variables being by reference so a straight 'copy' only gets you another reference.

However I have a lot of global variable objects in my home automation system and in a lot of cases - I'll get a copy of status and fiddle with it - eg
var thisDeviceStatus = global.get("maindevicestatus") ;
thisDeviceStatus.someParameter = someValue;
Then i'd put it back:- global.put(("maindevicestatus", thisDeviceStatus);

What I then discover is the global maindevicestatus.someParameter has also changed EVEN IF i excluded the global.put statement.

It seems this global.put is not necessary in this case. Is this a correct statement?

Many thanks

Coppo

Well, that is probably the understatement of the new decade! :grinning:

Well ... yes, sort-of.

While perhaps not strictly required right now, it may well become so in the future (near or far!). Node-RED may, in the future, act to better isolate context variables as newer versions of Node.js (JavaScript) become the standard.

Also, it is necessary if you have more than one context storage method defined. Since you have to tell it which to write to (otherwise, it writes to the default).

So it is good practice in all cases and necessary in some.

2 Likes

It is also necessary to use global.set if the variable is a simple value, such as a number or a string, rather than a javascript object.

Thanks. Do you know exactly what conditions cause the global variable to be updated when I edit the local 'copy'?

This is what alerted me to the problem - setting A 'DIRTY' flag in my local 'copy' of the global and dicsovering the global object DIRTY flag was also set! I didn't want the global version changed.

Most of my global data is objects.
Cheers
Coppo

JavaScript passes objects around by reference rather than by value. So the call to global.get() returns a reference to the object in context. Any modification of the object will modify the object in context.

If you want to modify the object without modifying what is in context, you have to clone it first. We provide the RED.util.cloneMessage function that can be used for this:

var value = RED.util.cloneMessage( global.get("myValue") );

However, I assume that isn't quite the case if you are using the file-based context store. Rather the in-memory copy of the variable is treated the same but not the file version.

You assume wrong. The file store uses an in memory cache in front of it.

Thanks folks. I do understand the referencing but not completely clear about when it is and isn't a 'by reference' variable. What I was trying to find out what is safe because I was seeing inconsistancy!

My understanding from what you have all said is that I always need to follow the following rules:-

a) If I want to update a global variable I always use global.put -( even though most of the time it wouldn't be needed)
b) if i don't want to update the global I clone it first

Does that cover it?
Cheers
Coppo

This only applies to Array and Object types.

If your context value is a string, boolean or number, and is at the top level of context (ie not a property inside an object or array), then you don't need to clone.