Search code examples
javascriptservicenowrhino

How can a JavaScript object be false and not null?


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?


Solution

  • 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);