JavaScript Operator ?.

operator ?. or optional chaning-operator allows you to check the object and its properties and methods for null and undefined, and if the object or its properties/methods are defined, then access its properties or methods:

let volume = null;
let bob = {name: "Bob"};

function printName(person){
    console.log(person.name);
}
printName(tom); // Uncaught TypeError: Cannot read properties of null (reading "name")
printName(bob);

In this case, the variable tom is null, so it does not have the property name. Accordingly, when passing this object to a function printName, we will get an error. In this case, we can check for null and undefined before accessing the object:

let volume = null;
let bob = {name: "Bob"};

function printName(person){
    if(person !==null && person !==undefined) console.log(person.name);
}
printName(tom); 
printName(bob); // Bob

We can also shorten the check:

function printName(person){
    if(person) console.log(person.name);
}

If person is null or undefined, it will if(person) return false.

However, the ?. offers a more elegant solution:

let volume = null;
let bob = {name: "Bob"};

function printName(person){
    console.log(person?.name);
}
printName(tom); // undefined
printName(bob); // Bob

An operator is indicated after the name of the object ?.- if the value is not equal to nulland undefined, then the property/method specified after the dot is accessed. If the value is null/undefined, then the property/method is not accessed. And on the console we will see undefined.

This operator can be used before accessing both properties and methods of an object:

let tom = undefined;
let bob = {
    name: "Bob", 
    sayHi(){
        console.log(`Hi! I am ${this.name}`);
    }
};

console.log(tom?.name); // undefined
console.log(bob?.name); // Bob
tom?.sayHi(); // not executed
bob?.sayHi(); // Hi! I am Bob

name In this case, the property and method are accessed sayHi()only if the objects tom and bob are not null/undefined.

Moreover, further down the chain of calls, check for the presence of a property or method in an object.

 
obj.val?.prop // property check
obj.arr?.[index] // check array
obj.func?.(args) // function check

Property check

An object can be defined but not have a property:

let tom = { name: "Tom"};
let bob = {
    name: "Bob", 
    company: {
        title: "Microsoft"
    }
};

console.log(tom.company?.title);    // undefined
console.log(bob.company?.title);    // Microsoft

Similarly, we can access the properties of an object using the array syntax:

let tom = { name: "Tom"};
let bob = {
    name: "Bob", 
    company: {
        title: "Microsoft"
    }
};

console.log(tom.company?.["title"]);    // undefined
console.log(bob.company?.["title"]);    // Microsoft

Checking an Array Property

Similarly, we can check for the existence of an array property before accessing its elements:

let tom = { name: "Tom"};
let bob = {
    name: "Bob", 
    languages: ["javascript", "typescript"]
};

console.log(tom.languages?.[0]);    // undefined
console.log(bob.languages?.[0]);    // javascript

Method Check

An object may also not have a method called on it. If the method is not defined, then when accessing the undefined method, we will encounter an error, in which case we can also check for the presence of the method:

let tom = { name: "Tom"};
let bob = {
    name: "Bob", 
    say(words){
        console.log(words);
    }
};

console.log(tom.say?.("my name is Tom"));   // undefined
console.log(bob.say?.("my name is Bob"));   // my name is Bob

Chain of checks

With the ? operator. you can create chains of checks by successively checking whether a value represents null/undefined:

</pre>
let sam = {name: "Sam"};
let tom = {
name: "Tom",
company: {title: "Google"}
};
let bob = {
name: "Bob",
company: {
title: "Microsoft",
print(){
console.log(`Company ${this.title}`)
}
}
};
sam?.company?.print?.(); // not called - no company property
tom?.company?.print?.(); // not called - no print method
bob?.company?.print?.(); // Microsoft company
<pre>