Mariam Reba Alexander

Checks and String comparison in Javascript

Created July 7, 2021

Here are some javascript tips on property check, string comparison & check for defined that you can use in your code.

Property check

We know that the method hasOwnProperty() can be used for checking whether a property exists in an object like the code below.

let object = { x: 1, y: 2 };
console.log(object.hasOwnProperty("x")); // true
console.log(object.hasOwnProperty("z")); // false
console.log(object.hasOwnProperty("toString")); //false 

You can see that hasOwnProperty() does not check the existence of inherited properties like toString() in an object.

An alternative is to use the in operator. I find it much shorter and can come in handy when one needs to check inherited properties.

let object = { x: 1, y: 2 };
console.log("x" in object); //true
console.log("z" in object); // false
console.log("toString" in object); //true 

Below is how in operator works in arrays.

let array = ["x", "y", "z"];
console.log("x" in array); //false
console.log("toString" in array); //true
console.log("0" in array); //true - index element 0

String comparison

Normally we compare strings using the <, > or === operators like below

console.log("zoo" < "ant"); // false - 'ant' comes before 'zoo'

Note that JavaScript strings are sequences of 16-bit integer values and string comparison is just a numerical comparison of the values in the two strings, that results in capital ASCII letters being “less than” all lowercase ASCII letters.

console.log("Zoo" < "ant"); // true - 'Zoo' comes before 'ant'

Therefore most developers follow the approach of converting the strings into either lowerCase or upperCase before comparing or sorting.

console.log("Zoo".toLowerCase() < "ant"); // false - now 'ant' comes before 'Zoo'

But things are not so simple in other languages. Spanish, for example treats ñ as a distinct letter that comes after n and before o. Lithuanian alphabetizes Y before J, and Welsh treats digraphs like CH and DD as single letters with CH coming after C and DD sorting after D.

String.localeCompare() takes locale-specific definitions of alphabetical order into account. For example

let items = ['réservé', 'Premier', 'Cliché', 'communiqué', 'café', 'Adieu'];
items.sort( (a, b) => a.localeCompare(b, 'fr', {ignorePunctuation: true}));
console.log(items);// ['Adieu', 'café', 'Cliché', 'communiqué', 'Premier', 'réservé']

But if you want to compare large arrays of language sensitive strings, it is better to use Into.collator constructor as it is more performant.

console.log(['Z', 'a', 'z', 'ä'].sort(new Intl.Collator('de').compare));
// expected output: ["a", "ä", "z", "Z"]

Refer Intl.Collator and String.localeCompare to know more.

Check for defined

Some check for defined variable or an object property in the following way

let object = { x: undefined, y: "hello" };
(object.x !== undefined || object.x !== null) ? object.x : "hi"; // "hi"

The above can be simplified by using the Logical OR (||) operator.

let object = { x: undefined, y: "hello" };
object.x || "hi" ; // "hi"

The || operator returns the first truthy value found, if both operands are falsy then the falsy value is returned. Falsy values include, false, null, undefined, 0 and "".

The first example can also be simplified using a Logical AND (&&) operator.

let object = { x: undefined, y: "hello" };
object.x && object.x || "hi" ; // "hi"

In the above code && operator returns true if and only if both its first operand and its second operand are true else it returns false. Here object.x && object.x returns false and therefore the result false || "hi" will return the truthy value i.e "hi".

However in certain cases we want the falsy values to be returned , for example the number 0 or the empty string "".

In this case, the operator ?? could be used instead. This operator returns the values that are not null or undefined.

let options = { timeout: 0, title: "", verbose: false, n: null };
options.timeout ?? 1000     // => 0: as defined in the object
options.title ?? "Untitled" // => "": as defined in the object
options.verbose ?? true     // => false: as defined in the object
options.quiet ?? false      // => false: property is not defined
options.n ?? 10             // => 10: property is null

Note that the ?? operator does not have higher precedence or lower precedence than the && and || operators, therefore you must use parenthesis explicitly.

(a ?? b) || c   // ?? first, then ||
a ?? (b || c)   // || first, then ??
a ?? b || c     // SyntaxError: parentheses are required

To be continued ...