Confusion about object prototype

Hi folks,

I'm working together with our friend @Paul-Reed on a new node.
But now we are completely stuck...

We create an object and pass it to a third-party library:

image

The library checks whether it is a plain object:

However seems that the second check fails:

Object.getPrototypeOf(obj) === Object.prototype

So I installed an npm library to find the differences between both prototypes, but it gives me no differences:

image

And when I convert the object to a json string and back to an object it is also fine:

image

I have no clue what is going wrong :woozy_face:

Does anybody can explain this behaviour and how I can solve it (without converting to a string and back)?

Thanks !!!!
Bart

Not an answer, but why are you doing the 2nd check? The first is surely good enough.

Hey Julian, that is not our check. It is code inside the Plotly library ...

OK, can you stick in a console.log of the obj? My guess is that it is receiving something that is an object not built from the Object.prototype.

Is the Function node involved at all?

This type of error can be caused by a gotcha with the Sandbox used inside the Function node.

The Sandbox gets its very own instance of Object. That means the prototype of an object created inside the Function node will not be the exact same thing as the prototype of the Object outside of the Sandbox.

The prototypes will be identical - but they will be separate instances of it - so the strict equality check will fail.

1 Like

how exactly do you create plotlyConfig.layout ?

Not really rocket science:

var plotlyConfig = {};
plotlyConfig.layout = {};
// Then the layout property is filled with sub-properties ...

Damn, don't know how you do it...
You are getting very warm ...
Plotly is made to run in the browser. But if you want to run it on the server - like we do for some features like validations - I needed to load it into JsDom. And JsDom uses the vm package, just like the function node:

image

Then it probably won't be easy to workaround this ...

It seems that I can get access to Plotly's internal vm context.
Perhaps I can use that (somehow) to create my instance inside the vm, to make sure it gets the correct prototype.
Something like this:

const createInstanceScript = new Script(`
   var plotlyConfig = {};
   plotlyConfig.layout = {};
   // Then the layout property is filled with sub-properties ...
`);

const jsDomVmContext = dom.getInternalVMContext();

createInstanceScript.runInContext(jsDomVmContext );

Although then I don't have access to my variable from my node ...
My time is up for today. If somebody has any ideas meanwhile, please let me know.

I managed to workaround it.
Here is the code, but I assume there is no poor soul on this planet that will ever need it ...
Anyway:

// Script to create a global variable
const script = new vm.Script(`
   this.plotlyConfig = {};
`);

// Execute the script in the VM, so that the global variable will be created in the VM context
const vmContext = jsDomInstance.getInternalVMContext();
script.runInContext(vmContext);

// Get the global variable from the VM context
var plotlyConfig = jsDomInstance.window.plotlyConfig;

// Manipulate the content of the global variable in the Node-RED node
plotlyConfig.someProperty = "someValue";

// Now you can call a function of the VM, and pass the plotlyConfig variable as a parameter ...

Since the variable has been created inside the VM context, its prototype will get through the check inside the VM ...

Without Nicks comment, I would most probably never have found the root cause in my current life ...

1 Like

The code snippet in my last post worked fine for a few objects. But I needed to add a large number of objects and arrays. And all those also needed to have a prototype from the VM, and I don't know in advance how much properties the user will add :cold_face:

So instead of creating a fixed number of instances in the VM, I got an idea to add two functions to the VM context. One function to create an object in the VM, and one to create an array in the VM:

// Script to add global functions (to create a Javascript object or array) in the server DOM context
const script = new vm.Script(`
   function createObject() {
      return {};
   }
            
   function createArray() {
      return [];
    }
`);

// Execute the script in the VM (of jsDom), so that the global function is added to the VM context
const vmContext = ´jsDomInstance.getInternalVMContext();
script.runInContext(vmContext);

Now in my node I can do this all over the place:

  • Replace someVar = {} by someVar = jsDomInstance.window.createObject()
  • Replace someVar = [] by someVar = jsDomInstance.window.createArray()

That is more like it ...

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.