Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Question mark syntax from CoffeeScript without CoffeeScript

CoffeeScript has such syntax sugar:

item.getFoo?().fooParam?.bar

Which translates into long javascript equivalent with getFoo==null and fooParam==null checks. The question is: are there any ways to use this syntax in vanilla javascript with a library/translator/compiler other than CoffeeScript? We use Traceur in our project, but it doesn't have such syntax because it is not ES6 compliant (although I wish it to). Maybe some way to implement it within Traceur fork?

like image 378
artch Avatar asked Sep 11 '14 09:09

artch


2 Answers

If you don't want the exact CoffeeScript semantics, you can cheat a bit:

return item.getFoo ? (item.getFoo().fooParam || {}).bar : undefined;

There are a few tricks going on here.

  1. The ternary operator is used to test the truthiness of item.getFoo
  2. If fooParam is missing, falsey, or absent, we substitute it with an empty object. CoffeeScript would have bailed out here.
  3. We return the value of bar regardless of whether it exists. If it does exist, you get the value you want. If it doesn't exist but fooParam is set, you get undefined. If it doesn't exist because fooParam was undefined and we fell back to {}, you still get undefined.

You can write some helpers if the ternary operator gets in the way:

function defaultObject(input) { // A helper to put somewhere
    return input || {};
}

return defaultObject((item.getFoo || defaultObject)().fooParam).bar;

This is even trickier: defaultObject will return {} when called with getFoo, so you don't need a ternary operator around the function call. If fooParam isn't truthy, defaultObject will return another empty object, eliminating the need for another ||. If fooParam is truthy, defaultObject behaves like the identity function and returns it.

I'm sure this could be golfed further down, but I'd recommend avoiding this pattern. Anyone reading your code will be fairly confused and blame you for making a mess in the codebase.

like image 186
mattbasta Avatar answered Nov 07 '22 10:11

mattbasta


I had this same question recently, and I came here hoping for a better solution than my current one. If you're doing this frequently, it's easier to make a function to do it for you:

var qm = function(arg) {
  if (arg instanceof Object) return arg;
  return function(){};
};

Then to use it, you wrap your objects in it to make sure no error is raised. It starts to look ugly if there are many question marks on a line

qm(qm(item.getFoo)().fooParam).bar
like image 30
willlma Avatar answered Nov 07 '22 11:11

willlma