Besides the fact that 2 years later, but with support of Babeljs even before, the best fitting solution should be based on Optional chaining, this Q remains a perfect target for practicing entirely function based approaches.
Implementing e.g. an afterThrowing
method modifier could result in an expression as short and as close as to the OP's pseudo code ...
try {
name = lead['Meta']['Name']['Full'];
} else try {
name = lead['Details']['Name']['First'] + " " + lead['Details']['Name']['Last'];
} catch (e) {
name = 'No Name';
}
... then would turn into something like ...
function getFullName(lead) {
return lead['Meta']['Name']['Full'];
}
function getComposedFullName(lead) {
return lead['Details']['Name']['First'] + " " + lead['Details']['Name']['Last'];
}
const name = (getFullName.afterThrowing((error, [data] = args) =>
(getComposedFullName.afterThrowing((/*error,[data]=args*/) => 'No Name')(data))
)(lead));
... implementation and example code as proof of concept ...
const leadTestSample = {
success: {
fullName: {
Meta: {
Name: {
Full: "Mary Jane Doe"
}
}
},
composed: {
Details: {
Name: {
First: "Jane",
Last: "Doe"
}
}
}
},
failure: {
Meta: {},
Details: {}
}
};
function getFullName(lead) {
return lead['Meta']['Name']['Full'];
}
function getComposedFullName(lead) {
return lead['Details']['Name']['First'] + " " + lead['Details']['Name']['Last'];
}
const nameDefault = 'No Name';
/*
try {
name = lead['Meta']['Name']['Full'];
} else try {
name = lead['Details']['Name']['First'] + " " + lead['Details']['Name']['Last'];
} catch (e) {
name = 'No Name';
}
*/
const fullNameData = leadTestSample.success.fullName;
const composedData = leadTestSample.success.composed;
const failureData = leadTestSample.failure;
console.log(
(getFullName.afterThrowing((error, [data] = args) =>
(getComposedFullName.afterThrowing(() => nameDefault)(data))
)(fullNameData))
);
console.log(
(getFullName.afterThrowing((error, [data] = args) =>
(getComposedFullName.afterThrowing(() => nameDefault)(data))
)(composedData))
);
console.log(
(getFullName.afterThrowing((error, [data] = args) =>
(getComposedFullName.afterThrowing(() => nameDefault)(data))
)(failureData))
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
<script>
(function (Function) {
const fctPrototype = Function.prototype;
const FUNCTION_TYPE = (typeof Function);
function isFunction(type) {
return (
(typeof type == FUNCTION_TYPE)
&& (typeof type.call == FUNCTION_TYPE)
&& (typeof type.apply == FUNCTION_TYPE)
);
}
function getSanitizedTarget(target) {
return ((target != null) && target) || null;
}
function afterThrowing/*Modifier*/(handler, target) {
target = getSanitizedTarget(target);
const proceed = this;
return (
isFunction(handler) &&
isFunction(proceed) &&
function () {
const context = target || getSanitizedTarget(this);
const args = arguments;
let result;
try {
result = proceed.apply(context, args);
} catch (exception) {
result = handler.call(context, exception, args);
}
return result;
}
) || proceed;
}
// afterThrowing.toString = () => 'afterThrowing() { [native code] }';
Object.defineProperty(fctPrototype, 'afterThrowing', {
configurable: true,
writable: true,
value: afterThrowing/*Modifier*/
});
}(Function));
</script>
I wouldn't mind if, at one day, JavaScript officially features ... Function.prototype[
before
|
after
|
around
|
afterThrowing
|
afterFinally
]
.