const obj = { a: { b: { c: { exists: true } } } };
const exists = obj?.a?.b?.c?.exists;
const obj = { a: { b: { c: { exists: true } } } };
const exists = obj?.a?.b?.c?.d?.e?.f?.g?.exists;
function getProperty(obj, path) {
if (typeof obj !== 'object' || obj === null) {
return undefined;
}
if (path.length === 0) {
return obj;
}
let current = obj;
for (let index = 0; index < path.length; index += 1) {
current = current[path[index]];
// If there is more path to traverse but the current value is not traversable, quit.
const isArray = Array.isArray(current);
const isObject = !isArray && typeof current === 'object' && current !== null;
if (!isObject && !isArray && (index + 1) < path.length) {
return undefined;
}
}
return current;
}
const obj = { a: { b: { c: { exists: true } } } };
const exists = getProperty(obj, 'a', 'b', 'c', 'exists');
function getProperty(obj, path) {
if (typeof obj !== 'object' || obj === null) {
return undefined;
}
if (path.length === 0) {
return obj;
}
let current = obj;
for (let index = 0; index < path.length; index += 1) {
current = current[path[index]];
// If there is more path to traverse but the current value is not traversable, quit.
const isArray = Array.isArray(current);
const isObject = !isArray && typeof current === 'object' && current !== null;
if (!isObject && !isArray && (index + 1) < path.length) {
return undefined;
}
}
return current;
}
const obj = { a: { b: { c: { exists: true } } } };
const exists = getProperty(obj, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'exists');
--enable-precise-memory-info
flag.
Test case name | Result |
---|---|
?. operator (results in defined value) | |
?. operator (results in undefined value) | |
getProperty (results in defined value) | |
getProperty (results in undefined value) |
Test name | Executions per second |
---|---|
?. operator (results in defined value) | 6208473.0 Ops/sec |
?. operator (results in undefined value) | 5825148.5 Ops/sec |
getProperty (results in defined value) | 1164066.8 Ops/sec |
getProperty (results in undefined value) | 1001086.1 Ops/sec |
Let's break down the benchmark and explain what is being tested, compared, and the pros and cons of each approach.
Benchmark Overview
The benchmark is testing two approaches to access nested properties of an object: using the optional chaining operator (?.
) and a custom getProperty
function.
Optional Chaining Operator (?.
)
The optional chaining operator is a new feature in JavaScript introduced in ECMAScript 2020. It allows you to access nested properties of an object without throwing an error if any of the intermediate steps are null or undefined.
Example:
const obj = { a: { b: { c: { exists: true } } } };
const exists = obj?.a?.b?.c?.exists; // returns true if exists is defined, otherwise undefined
The benchmark tests two scenarios:
exists
is defined (obj?.a?.b?.c?.exists
), the operator should return a defined value.exists
is not defined (e.g., due to an extra key like d
in the object), the operator should return undefined.Custom getProperty
Function
The custom function getProperty
takes an object and a path as arguments. It traverses the object using the path, checking if each intermediate step is null or undefined. If it encounters an undefined value, it immediately returns undefined.
Example:
function getProperty(obj, ...path) {
// ...
}
const obj = { a: { b: { c: { exists: true } } } };
const exists = getProperty(obj, 'a', 'b', 'c', 'exists'); // returns true if exists is defined, otherwise undefined
The benchmark tests two scenarios:
exists
is defined (getProperty(obj, 'a', 'b', 'c', 'exists')
), the function should return a defined value.exists
is not defined (e.g., due to an extra key like d
in the object), the function should return undefined.Comparison and Pros/Cons
Both approaches have their pros and cons:
?.
)getProperty
FunctionOther Considerations
The benchmark also measures the execution speed of each approach, which can be influenced by factors like:
When choosing between these approaches, consider the trade-off between conciseness, readability, and control over behavior. If you need more predictability and flexibility, the custom getProperty
function might be a better choice. Otherwise, the optional chaining operator (?.
) can simplify your code and improve performance in most cases.
As for the benchmark results, they show that:
?.
) is generally faster than the custom getProperty
function.getProperty
function provides more control over error handling and behavior, but at a slightly higher cost in terms of execution speed.