3

We all know the basic escaping mechanism in JS:

try {
    ...
}
catch(err) {
    ..
}

I have a JSON data in which I want to check if a lead has a full name. If not, try to compose one with first and last name fields (I actually hard code a space there which is a problem as well.) and finally if all fails show "No Name".

Or in pseudo code:

try {
    name = lead['Details']['Name']['Full'];
} else try {
    name = lead['Details']['Name']['First'] + " " + lead['Details']['Name']['Last'];
} catch (e) {
    name = "No Name";
}

Any suggestions?

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
Ben
  • 2,957
  • 2
  • 27
  • 55
  • 2
    _"Any suggestions?"_ yes, use conditional logic instead, ie `if` – Phil Aug 22 '18 at 02:42
  • @Phil, I also cannot for sure tell I will have 'Details', or 'Name' so I will end up with many ifs. I am looking for a method similar to Rails' "dig" – Ben Aug 22 '18 at 02:44
  • If only JS had null conditional operators :( Although I guess [Stage 1](https://github.com/tc39/proposal-optional-chaining) is better than nothing. – Tyler Roper Aug 22 '18 at 02:45

3 Answers3

4

You could nest your second try/catch block in the exception block of the first try/catch block as follows:

try {
    name = lead['Details']['Name']['Full'];
} catch(ex0) {      
  try {
      name = lead['Details']['Name']['First'] + " " + lead['Details']['Name']['Last'];
  } catch (ex1) {
      name = "No Name";
  }
}

This is valid syntax, and functionally equivalent to what you're requiring

Dacre Denny
  • 29,664
  • 5
  • 45
  • 65
  • That'll work. Not the most beautiful function I ever saw, but there seems to be no other solution. I had to run a try/catch on lead['Details']['Name'] since it may be empty. What if lead['Details']['Name']['First'] is empty but not lead['Details']['Name']['Last'] ? are we going to get a full name or will it go to the catch? I think another failsafe may be needed there. What do you think? – Ben Aug 22 '18 at 03:37
0

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].

Peter Seliger
  • 11,747
  • 3
  • 28
  • 37
0

Instead of do this in using one try-catch block only. As we know when we will get type error in javascript when access something that does not exist.

See the below code snippet.

function getName(isFullName='true'){

  try{
     if(isFullName)
       name = lead['Details']['Name']['Full'];       
     else
       name = lead['Details']['Name']['First'] + " " + lead['Details']['Name']['Last'];       
     }
   catch(e){
     if (e instanceof TypeError && isFullName) 
         getName(false);
     name = 'No name';   
    }
} 

In case name is full name is coming undefined then, we need to add an extra if block to check for the undefined case.

Rishu Ranjan
  • 494
  • 4
  • 7