ServiceNow: reference vs. primitive data types

mkrcma

Marek Krčma

Posted on March 23, 2023

ServiceNow: reference vs. primitive data types

Following code shows the correct and bad way how to work with field values using GlideRecord. It simply puts values into an array. Take time and go through the code, all explained after in detail:

var prbArray_CORRECT = [];
var prbArray_WRONG = [];
var grPrb = new GlideRecord('problem');
grPrb.addQuery('active', true);
grPrb.query();
while(grPrb.next()) {
    // grPrb is iterable collection, it moves to the next element with each iteration
    // grPrb.number is object GlideElement, not string/integer/date
    // reference is pushed to array
    // Wrong way
    prbArray_WRONG.push(grPrb.number);
    // Correct way
    // grPrb.getValue('number') returns string
    // The same can be done by explicit retype:
    // grPrb.number + '';
    // grPrb.number.toString();
    // grPrb.number.getValue();
    prbArray_CORRECT.push(grPrb.getValue('number'));
}
gs.log(prbArray_CORRECT);
// Correct output: PRB0040003,PRB0040004,PRB0040005,PRB0040006,PRB0040007

gs.log(prbArray_WRONG);
// Unexpected output: PRB0040007,PRB0040007,PRB0040007,PRB0040007,PRB0040007
// Array prbArray_WRONG contains elements with the same value


Enter fullscreen mode Exit fullscreen mode

The issue is prbArray_WRONG which stores unexpected values (all values are the same: PRB0040007,PRB0040007,PRB0040007,...) even though there were simply saved values of field grPrb.number for active problems. To tell what is happening, it is important to explain two principles.

The first is related to JavaScript and the second is related to ServiceNow.

Object vs. primitive data type

First principle: when assigning value to a variable, the type of value matters in JavaScript. Primitive types (string, integers, boolean, null) are assigned directly as value, no confusion here. But object types are assigned as reference and are treated more as the pointer somewhere into memory where the object is stored. This is an important difference because it has consequences when working with objects.

ServiceNow GlideElement

The second principle is related to ServiceNow and is also a tricky one. Which type of value would you expect in grPrb.number? Let's try this:

// Is grPrb.number a string?
var grPrb = new GlideRecord('problem');
grPrb.addQuery('active', true);
grPrb.setLimit(1);
grPrb.query();
if (grPrb.next()) {
    gs.log(typeof grPrb.number);
    // Returns "object"
    gs.log(grPrb.number.constructor.name);
    // Returns "GlideElement"
}
Enter fullscreen mode Exit fullscreen mode

ServiceNow GlideElement

Well, right, ehm it is object GlideElement. And this is the confusing part, because logically I would expect string (primitive type) in grPrb.number.

When connecting these two principles, it explains what is happening:
1) Putting grPrb.number into array means there is put reference to GlideElement object in each iteration instead of actual value of field
2) When the records' iteration is done, all array elements reference to the last GlideElement. Because "grPrb" is iterable > the current pointer is the last record at the end of iteration > all elements in the array now point to this last record.

Confusing? Yes, it is not easy to get it and explain it. Important is to keep in mind that whenever you do something with GlideRecord fields, just retype the value to the string or any other primitive data type to avoid unexpected behavior. GlideElement provides a set of methods for dealing with fields and their values (see documentation). When you convert into the primitive data type, it will be handled as value (not as object reference) in the array element/variable. It will save you headache and hours of debugging. As mentioned in the script, you can retype it in the following ways:

var prbNumber = grPrb.number + "";
var prbNumber = grPrb.number.toString();
var prbNumber = grPrb.number.getValue();
var prbNumber = grPrb.getValue('number');
var recordSysID = grPrb.getUniqueValue();

If you need to pass a record sys_id as an event parameter or a parameter in script include, you can use getUniqueValue() GlideRecord method.


No matter if you work with field number, description, priority, sys_id the behavior is the same: GlideElement represents the field and if you need a field value, you need to use getValue(), toString() methods or explicitly retype it.

If you want to go deeper (and I recommend it) and understand the differences of how the primitive and reference data types work in JavaScript, check these posts. This principle is general and is fundamental for object-oriented programming languages. It is more technical but interesting to understand how computer works with memory:
https://www.freecodecamp.org/news/primitive-vs-reference-data-types-in-javascript/

https://ui.dev/primitive-vs-reference-values-in-javascript

💖 💪 🙅 🚩
mkrcma
Marek Krčma

Posted on March 23, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related