Оператор ?.
Оператор ?. или optional chaning оператор позволяет проверить объект и его свойства и методы на null и undefined, и если объект или его свойства/методы определены, то обратиться к его свойствам или методам:
let tom = null;
let bob = {name: "Bob"};
function printName(person){
console.log(person.name);
}
// Uncaught TypeError: Cannot read properties of null (reading "name")
printName(tom);
printName(bob);
В данном случае переменная tom равна null, соответственно у ней нет свойства name. Соответственно при передаче этого объекта в функцию printName мы получим ошибку. В этом случае мы можем перед обращением к объекту проверять его на null и undefined:
let tom = null;
let bob = {name: "Bob"};
function printName(person){
if(person !==null && person !==undefined) console.log(person.name);
}
printName(tom);
// Bob
printName(bob);
Также мы можем сократить проверку:
function printName(person){
if(person) console.log(person.name);
}
Если person равен null или undefined, то if(person) возвратит false.
Однако оператор ?. предлагает более элегантный способ решения:
let tom = null;
let bob = {name: "Bob"};
function printName(person){
console.log(person?.name);
}
// undefined
printName(tom);
// Bob
printName(bob);
После названия объекта указывается оператор ?. — если значение не равно null и undefined, то идет обращение к свойству/методу, которые указаны после точки. Если же значени равно null/undefined, то обращения к свойству/методу не происходит. И на консоли мы увидим undefined.
Данный оператор можно использовать перед обращением как к свойствам, так и к методам объекта:
let tom = undefined;
let bob = {
name: "Bob",
sayHi(){
console.log(`Hi! I am ${this.name}`);
}
};
// undefined
console.log(tom?.name);
// Bob
console.log(bob?.name);
// не выполняется
tom?.sayHi();
// Hi! I am Bob
bob?.sayHi();
В данном случае обращение к свойству name и методу sayHi() происходит только в том случае, если объекты tom и bob не равны null/undefined.
Более того далее по цепочке вызывов проверять наличие свойства или метода в объекте:
// проверка свойства
obj.val?.prop
// провера массива
obj.arr?.[index]
// проверка функции
obj.func?.(args)
Проверка свойства
Объект может быть определен, однако не иметь какого-то свойства:
let tom = { name: "Tom"};
let bob = {
name: "Bob",
company: {
title: "Microsoft"
}
};
// undefined
console.log(tom.company?.title);
// Microsoft
console.log(bob.company?.title);
Подобным образом мы можем обращаться к свойствам объекта с помощью синтаксиса массивов:
let tom = { name: "Tom"};
let bob = {
name: "Bob",
company: {
title: "Microsoft"
}
};
// undefined
console.log(tom.company?.["title"]);
// Microsoft
console.log(bob.company?.["title"]);
Проверка свойства-массива
Аналогично мы можем проверять наличие свойства-массива перед обращением к его элементам:
let tom = { name: "Tom"};
let bob = {
name: "Bob",
languages: ["javascript", "typescript"]
};
// undefined
console.log(tom.languages?.[0]);
// javascript
console.log(bob.languages?.[0]);
Проверка метода
Объект также может не иметь вызываемого у него метода. Если метод не определен, то при обращении к неопределенному методу мы столкнемся с ошибкой, и в этом случае также можно проверять наличие метода:
let tom = { name: "Tom"};
let bob = {
name: "Bob",
say(words){
console.log(words);
}
};
// undefined
console.log(tom.say?.("my name is Tom"));
// my name is Bob
console.log(bob.say?.("my name is Bob"));
Цепочка проверок
С помощью оператора ?. можно создавать цепочки проверок, последовательно проверяя, представляет ли значение null/undefined:
let sam = {name: "Sam"};
let tom = {
name: "Tom",
company: { title: "Google"}
};
let bob = {
name: "Bob",
company: {
title: "Microsoft",
print(){
console.log(`Компания ${this.title}`)
}
}
};
// не вызывается - нет свойства company
sam?.company?.print?.();
// не вызывается - нет метода print
tom?.company?.print?.();
// Компания Microsoft
bob?.company?.print?.();