Skip to main content
Version: 11.2

UDB extension functions

note

This article documents the .usoft extension functions mentioned in the Object extension functions section of Revised web UI API in USoft 11. These functions are implemented in usoft.module.util.js, and are added to the prototypes of Object, Array, Date and String, so that they become available on (almost) any value of that type, anywhere in your code.

Why a .usoft extension

USoft 10.1 added extra functionality directly onto the prototypes of native JavaScript types, e.g. .forEachValue(), .forEachKey(), .map(). Adding methods directly onto native prototypes like this risks clashing with methods of the same name added by third-party libraries, or by a later version of JavaScript itself — which is exactly what happened with .map(), since the language has since added its own native Array.prototype.map() with different behavior.

To avoid this, USoft 11 moved all of this functionality (and, since then, some additional functions as well) behind a single, non-enumerable .usoft property on the affected prototypes. This keeps the native prototypes themselves untouched — nothing shows up in a for...in loop or JSON.stringify() because of it — while still making the functions available from any value of that type.

Syntax

value.usoft.functionName( ...args )
note

Each of the four types listed below defines its own, separate .usoft property; they are not inherited or merged. Even though every array and every string is also an object, someArray.usoft only exposes the array-specific functions below, not the generic object functions (and likewise for strings). Also, because .usoft is implemented as a getter, value.usoft computes and returns a small, fresh object every time it is accessed — it is not the same object reference from one access to the next, so always chain straight into the function you want to call.

The functions below are only the ones exposed through .usoft. There are more USoft-specific functions elsewhere in the API that are not part of this extension — this article covers .usoft specifically, not the API as a whole.

Object extension functions

Available on any plain object, through Object.prototype.usoft.

FunctionExplanation
.equals(other)Deep-compares this object against other, recursing into nested objects and arrays.
.forEachKey(fn)Calls fn(key, value, object) for every enumerable property.
.forEachValue(fn)Calls fn(value, key, object) for every enumerable property.
.findObject(fn)Returns the first property value for which fn(value, key, object) is truthy.
.findKey(fn)Returns the first property key for which fn(value, key, object) is truthy.
.filterObject(fn)Returns a new object containing only the properties for which fn(value, key, object) is truthy.
.map(fn)Returns a new object with the same keys, whose values are the result of fn(value, key, object).
.mapArray(fn)Returns an array containing the result of fn(value, key, object) for every property, discarding the keys.

Examples

let sizes = { S: 10, M: 25, L: 15 };

sizes.usoft.forEachKey((size, count) => {
console.log(`${size}: ${count}`);
});
// S: 10
// M: 25
// L: 15

let inStock = sizes.usoft.filterObject((count) => count > 0);
// { S: 10, M: 25, L: 15 }

let labels = sizes.usoft.mapArray((count, size) => `${size} (${count})`);
// [ "S (10)", "M (25)", "L (15)" ]

let a = { NAME: 'Jones', AGE: 42 };
let b = { NAME: 'Jones', AGE: 42 };
a.usoft.equals(b); // true, even though a !== b

Array extension functions

Available on any array, through Array.prototype.usoft.

FunctionExplanation
.clear()Empties the array in place, and returns the removed elements.
.contains(value)Returns whether value occurs in the array.
.compact()Returns a new array with every undefined element removed.
.equals(other)Deep-compares this array against other, recursing into nested objects and arrays.
.merge(newArr, unique)Pushes every element of newArr onto this array, in place. If unique is true, elements already present (per .contains()/.containsObject()) are skipped.
.containsObject(value)Like .contains(), but for plain objects: returns whether the array contains an element whose properties all match value's.
.pushUnique(value)Pushes value onto the array only if it (or, for a plain object, a matching element) is not already present. Returns the array's new length either way.

Examples

let colors = ['red', 'green'];

colors.usoft.contains('green'); // true
colors.usoft.pushUnique('green'); // 2, 'green' was already there
colors.usoft.pushUnique('blue'); // 3

let users = [{ ID: 1, NAME: 'Jones' }];
users.usoft.containsObject({ ID: 1, NAME: 'Jones' }); // true, even though it's a different object instance

let raw = [1, undefined, 2, undefined, 3];
raw.usoft.compact(); // [1, 2, 3]

Date extension functions

Available on any Date instance, through Date.prototype.usoft. Parsing a formatted string into a Date, however, is a static function on Date itself rather than a .usoft function, since there is no Date instance to call it on yet at that point:

Date.parseDate( '31-12-2025', 'DD-MM-YYYY' ); // a new Date instance
FunctionExplanation
.dateFormat(format)Formats the date as a string, according to format.
.add(amount, type)Returns a new Date, amount type later (or earlier, for a negative amount) than this one. Type is one of 'years', 'months', 'weeks', 'days', 'hours', 'minutes' or 'seconds'.
.dayOfYear()Returns the ordinal day of the year (1-366) that this date falls on.
.week()Returns the ISO 8601 week number that this date falls in.

Format uses the same mask syntax as $.udb.ioFormat, which is what both .dateFormat() and Date.parseDate() use internally.

Examples

let today = new Date();

today.usoft.dateFormat('DD-MM-YYYY'); // e.g. '10-08-2026'
today.usoft.add(1, 'months'); // a new Date, one month after today
today.usoft.add(-7, 'days'); // a new Date, a week before today
today.usoft.dayOfYear(); // e.g. 222
today.usoft.week(); // e.g. 33

String extension functions

Available on any string, through String.prototype.usoft.

FunctionExplanation
.contains(...values)Returns whether the string contains every one of the given substrings.
.containsAny(...values)Returns whether the string contains any of the given substrings.
.anyOf(...values)Returns whether the string itself exactly equals one of the given values — a convenient "is this one of..." check.
.encodeHTML()Returns the string with &, <, >, " and ' replaced by their HTML entity equivalents.
.format(values)Replaces {0}, {1}, ... placeholders in the string with the corresponding element of the values array, or {key} placeholders with the corresponding property of the values object.
.toKebabCase()Converts a camelCase or PascalCase string to kebab-case.
.toInitCaps(lower)Capitalizes the first character. Unless lower is false, the rest of the string is lowercased as well.
.expandNumericalExponent()Expands a string containing scientific notation (e.g. '1.5E+3') into plain decimal notation.
.diff(otherString)Returns an array of { mode, string } segments (mode being 'left', 'right' or 'same') describing the character-level differences between this string and otherString.

Examples

'uiButtonControl'.usoft.toKebabCase(); // 'ui-button-control'
'usoft'.usoft.toInitCaps(); // 'Usoft'

'Hello {0}, you have {1} messages'.usoft.format(['Jones', 3]);
// 'Hello Jones, you have 3 messages'

'Hello {name}, you have {count} messages'.usoft.format({ name: 'Jones', count: 3 });
// 'Hello Jones, you have 3 messages'

'<script>'.usoft.encodeHTML(); // '&lt;script&gt;'

'DEPARTMENT'.usoft.contains('PART', 'MENT'); // true, contains both substrings
'DEPARTMENT'.usoft.containsAny('XYZ', 'MENT'); // true, contains at least one

let role = 'MANAGER';
role.usoft.anyOf('MANAGER', 'DIRECTOR', 'OWNER'); // true, role is one of these