When working with objects, you sometimes need to check if a property exists and do something if it doesn't. The easiest way to do this is to check it against undefined
, yet this approach is not universal. Sometimes it just won't work as expected.
if (obj.key === undefined) {
// the logic
}
Imagine a function that has to count the number of identical elements in an array:
// Log in
const bag = [
'apple', 'banana', 'pear',
'apricot', 'apple', 'banana',
'apple', 'orange', 'pear',
];
// Exit
const result = {
apple: 3,
banana: 2,
pear: 2,
orange: 1,
apricot: 1,
};
Its algorithm is simple enough, but there is one subtle point. While iterating over the array, this function takes the result object, extracts the desired property from it, and increments the value by one. But this is in cases where the property already exists. What if it doesn't? The first time an element appears, a relevant property with a value of 1 in the result
object since it's initially empty. Look at how it's implemented:
const countFruits = (fruits) => {
const result = {};
for (const name of fruits) {
// Checking if it exists
if (result[name] === undefined) {
result[name] = 1;
} else {
result[name] += 1;
}
}
return result;
};
In a situation like this, comparing a value to undefined
will always work, but only because undefined
cannot be inside an existing property. But this isn't always the case. Look at this code:
const obj = {
key: doSomething(),
};
In the above example, the key
value is the result of calling doSomething()
. If this function can return undefined
, it will appear that the key
is defined in the object, but its value is undefined
.
In JavaScript, there is a more reliable and more proper way to check the existence of property without comparing values, using the Object.hasOwn() method. This is how the countFruits()
, function changes if you use this property:
const countFruits = (fruits) => {
const result = {};
for (const name of fruits) {
// Checking if it exists
if (Object.hasOwn(result, name)) {
result[name] += 1;
} else {
result[name] = 1;
}
}
return result;
};
Nullish coalescing operator
In our fruit search example, you can't just have undefined
as a value inside the result object. There will always be a number, starting from one. Moreover, even checking if the value exists is superfluous. All we need to do is retrieve the current value and be able to set a default value. You can do this by using the nullish coalescing operator. It allows you to set a default value when the value is null
or undefined
.
let value;
value ?? 'wow'; // 'wow'
value = null;
value ?? 'wow'; // 'wow'
value = true;
value ?? 'wow'; // true
for (const name of fruits) {
result[name] = (result[name] ?? 0) + 1;
}
Recommended materials
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.