There is a common error in JavaScript that occurs when you try to access a property or a method of a variable that is either null or undefined.
let user = {
name: "Alice",
address: {
street: "Main Street",
city: "New York",
},
job: null
};
// TypeError: Cannot read properties of null
// console.log(user.job.name);
// TypeError: Cannot read properties of undefined
// console.log(user.x.y)There is no definitive answer to when you should check if an object property is null, undefined, or exists, as it depends on the context and the purpose of your code. It’s critical to fully understand following methods before using any of them.
typeof operator to check if a property is undefined. It will return "undefined" for both undefined and undeclared values, so it cannot tell if a property exists or not. It will return "object" for both null and object values, so it cannot distinguish between them.let obj = {a: 1};
console.log(typeof obj); // "object"
console.log(typeof obj.a); // "number"
console.log(typeof obj.b); // "undefined"
console.log(typeof null); // "object"==, ===) to check if property is null, undefined, or both.The equality operator (==) will compare two values for equality after doing any necessary type conversions. This means that null and undefined are equal to each other, but not to anything else.
null == undefined // true
null == 0 // false
null == false // false
null == "" // false
undefined == 0 // false
undefined == false // false
undefined == "" // falseThe strict equality operator (===) will compare two values for equality without doing any type conversion. This means that null and undefined are only equal to themselves, and not to any other value.
null === undefined // false
null === 0 // false
null === false // false
null === "" // false
undefined === 0 // false
undefined === false // false
undefined === "" // falseThe strict equality operator is usually preferred over the equality operator, as it avoids unexpected results due to type coercion.
let person = {
name: "Alice",
age: null
};
console.log(person.name === null); // false
console.log(person.age === null); // true
console.log(person.address === null); // false
console.log(person.address === undefined); // truenull or undefined. Be aware that it will also treat other falsy values (such as false, 0, "", NaN) as equivalent.const person = {
name: "John Doe",
age: 25,
address: null,
phone: undefined,
email: "", // empty string
};
for (let prop in person) {
if (person[prop]) {
console.log(`${prop}: ${person[prop]}`);
}
}
// name: John Doe
// age: 25_.isNil() function to check if object property is null or undefined.var _ = require("lodash");
var obj = {
name: "Charlie",
age: 30,
hobbies: ["cooking", "biking", "gardening"],
address: null,
score: 0,
email: undefined
};
for (var prop in obj) {
if (_.isNil(obj[prop])) {
console.log(prop + ": " + obj[prop]);
}
}
// address: null
// email: undefinedin operator or hasOwnProperty method to check if a property exists. The in operator returns true if the property is found in the object or its prototype chain. The hasOwnProperty method returns true if the property is found in the object itself, and false if it is inherited or not found.let obj = { prop1: "value1", prop2: undefined };
console.log("prop1" in obj); // true
console.log("prop2" in obj); // true
console.log("prop3" in obj); // false
console.log("toString" in obj); // true, inherited from Object.prototype
console.log(obj.hasOwnProperty("prop1")); // true
console.log(obj.hasOwnProperty("prop2")); // true
console.log(obj.hasOwnProperty("prop3")); // false
console.log(obj.hasOwnProperty("toString")); // false, inherited from Object.prototype=== or typeof to check undefinedUsing === to check undefined is safe, as long as you are sure that the variable or property you are checking has been declared. However, if you try to access a variable or property that does not exist, you will get a ReferenceError.
// x is declared but not assigned a value
var x;
console.log(x === undefined); // true
// y is not declared
console.log(y === undefined); // ReferenceError: y is not definedTo avoid this error, you can use the typeof operator, which returns a string indicating the type of the operand. If the operand is undefined or not declared, it will return “undefined” as well.
// x is declared but not assigned a value
var x;
console.log(typeof x === "undefined"); // true
// y is not declared
console.log(typeof y === "undefined"); // trueAnother reason to use typeof instead of === is that the global variable undefined can be overwritten in ES3, which can cause unexpected results when comparing with ===.
// In ES3, undefined can be redefined
window.undefined = "foo";
console.log("foo" === undefined); // true
// Using typeof is safer
console.log(typeof "foo" === "undefined"); // falseHowever, this issue has been fixed in ES5, and undefined is non-writable in modern browsers.
Accessing deeply nested properties is error prone, you need to check null and undefined on every step of the chain, not just the target property.
It’s recommended to using optional chaining (?.) to access properties or methods of a variable that might be null or undefined. This operator returns undefined if any part of the chain is null or undefined, instead of throwing an error.
let user = {
name: "Alice",
address: {
street: "Main Street",
city: "New York",
},
};
// Without optional chaining, we need to check if user and user.address exist
console.log(user && user.address && user.address.street); // Main Street
// TypeError: Cannot read properties of undefined
// console.log(user.job.company);
// With optional chaining, we can write it more concisely
console.log(user?.address?.street); // Main Street
console.log(user?.job?.company); // undefinedYou can use optional chaining in combination with truthy evaluation, equality operators, and typeof to check if a property value or nullish coalescing operator (??) to provide a default value.