2

From within a ServiceNow script, I am trying to detect whether or not something is defined.

On this page it says

All values are truthy unless they are defined as falsy. That is, all values are truthy except false, 0, -0, 0n, "", null, undefined, and NaN.

Thus, any JavaScript object must be true unless it is null.

Yet consider this ServiceNow code which prints some information about an Incident that was created by a Record Producer which had a variable named location.

var incGR = new GlideRecord('incident');
incGR.get('49eab040975d6510378377500153afe8');
gs.info(typeof incGR.variables);
gs.info(incGR.variables ? true : false);
gs.info(incGR.variables.location);
gs.info(incGR.variables.constructor.name);

When run as a background script, it prints the following:

*** Script: object
*** Script: false
*** Script: 8269b993db7d3200860930cf9d961945
*** Script: GlideElementVariables

Now I understand that incGR and incGR.variables are actually Java objects (created in an old version of the Rhino engine). Still, how can incGR.variables be false if it is a non-empty object?

giles3
  • 465
  • 2
  • 9
  • 1
    `typeof null` is `'object'`. – Unmitigated Mar 31 '23 at 21:50
  • @Unmitigated If an object is null then obviously it is false. But this is not null, and yet it is still false. – giles3 Mar 31 '23 at 21:59
  • What happens if you put a second `gs.info(incGR.variables ? true : false);` after the first? On the face of it the property lookup is not always returning the same value. BTW, `null` is not an object in JavaScript, it's has its own data type, "null". (`typeof` is so entrenched it can't be corrected). – traktor Mar 31 '23 at 22:24
  • Trying `gs.info(incGR.variables === null)` first off could also be revealing. – traktor Mar 31 '23 at 22:46
  • `gs.info(incGR.variables === null)` prints `false`. The behavior is consistent regardless of the order of the statements. – giles3 Mar 31 '23 at 23:11

1 Answers1

1

Worth pointing out several things:

We classify Booleans in JS into "truthy" and "falsy"

Truthy means it will cause an if or ? to be used; falsy means it will go to the else or :.

So in this statement of yours:

Thus, any JavaScript object must be true unless it is null.

I think you meant:

Thus, any JavaScript object must be truthy unless it is falsy.

But we understand what you mean, don't worry!

This is the puzzle you face

How can incGR.variables ? true : false be false and yet there be values for incGR.variables.location and incGR.variables.constructor.name?

That is indeed a puzzle to me too. I agree with you that the only way incGR.variables.location can have a value (in this case, a string), is for incGR.variables to be an object, and therefore be truthy.

Possible solutions

Have you checked whether it might not be a standard Javascript object? Might there be a "getter" that specifically responds with a "falsy" value for incGR.variables but does give proper values for incGR.variables.location?

You could further help debugging by adding this line:

gs.info(JSON.stringify(incGR.variables,null,2));

and reporting the result.

You could "launder" it to make it behave properly

Doing the following will turn it into a proper Javascript object.

var incGR = new GlideRecord('incident');
incGR.get('49eab040975d6510378377500153afe8');

const incGR_js = JSON.parse(JSON.stringify(incGR));

gs.info(typeof incGR_js.variables);
gs.info(incGR_js.variables ? true : false);
gs.info(incGR_js.variables.location);
gs.info(incGR_js.variables.constructor.name);
ProfDFrancis
  • 8,816
  • 1
  • 17
  • 26
  • It is definitely NOT a standard JavaScript object. – giles3 Mar 31 '23 at 22:12
  • If I try to stringify it I get a bunch of values including `"location":{}`. – giles3 Mar 31 '23 at 22:14
  • If I print the value of `incGR.variables.location.constructor.name` it prints `GlideElementVariable`. – giles3 Mar 31 '23 at 22:16
  • "Might there be a getter that specifically responds with a falsy value?". Most likely. There is probably a "getter" somewhere in the Java code (which I cannot see) that is causing a falsy value to be returned in this particular context. – giles3 Mar 31 '23 at 22:27
  • So how did you get on with the "laundering" approach? – ProfDFrancis Apr 01 '23 at 15:00
  • 1
    The laundering does not work. When you `stringify` the parent object you get a bunch of empty child objects. But we know that the child objects are not really empty, because they have properties, and when you print them they have values. I guess this proves that these are not "standard" JavaScript objects. They are Rhino objects. And the standard rules do not apply. – giles3 Apr 02 '23 at 16:28
  • So you may need to iterate over them to read them individually and put them into a JS object that behaves more predictably. – ProfDFrancis Apr 02 '23 at 16:31