ServiceNow: reference vs. primitive data types
Marek Krčma
Posted on March 23, 2023
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
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"
}
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/
Posted on March 23, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.