2

This is a function that searches child nodes recursively until it finds one that is a text:

_.findPrevText = (node) => {
  if (node.nodeType === 3) return node
  return _.findPrevText(node.lastChild)
}

I could also write it like this:

_.findPrevText = (node) => {
  if (node.nodeType !== 3) return _.findPrevText(node.lastChild)
  return node
}

Which style is cleaner/readable (or has better performance)?

1
  • 1
    Some would say the cleanest version uses only one return statement at all: { return node.nodeType !== 3 ? _.findPrevText(node.lastChild) : node; }. They would say that if there's too much code you can assign a value to a variable and return that variable, keeping the single return at the end.
    – Erik Eidt
    May 4, 2016 at 16:27

2 Answers 2

5

In terms of speed of execution they are the same. The compiled/interpreted code is going to do a test if nodetype == 3. If yes it executes a return statement next. If no it executes the other return statement next. Both cases are going to execute a return statement next.

In terms of stack usage, they are the same. In both examples shown, it only drops into the recursive call if it cannot match nodetype == 3. It is possible to write the code poorly so that unnecessary recursive calls happen. But such is not the case in the examples shown. So memory usage they are the same.

If null is a possible value for nodetype they are still the same. The two examples will both drop into the recursive call whether nodetype == 2 or nodetype == null. You could rewrite the examples to also test for null and not drop into recursion on nulls. But that wasn't the question asked.

The only difference may be in readability. Which is more readable? Positive statements take one less mental step so (nodetype == 3) is a little less mental work than (nodetype != 3). But marginally so.

1
  • I also thought about the last point. It's something that's also applicable in creative and technical writing. Thanks for the advice.
    – alex
    May 4, 2016 at 16:32
2

It is conventional in recursive functions to write the base case first. That means your first option. Your second option is testing for the inverse of the base case, which is confusing to read. Writing the base case first makes little difference in this particular case, but in the general case if you were to use pattern matching, or a switch statement, or an if-else chain, it is usually much cleaner to write the base case first. Also, the recursive case is frequently much more verbose than the base case. Hence the convention.

Note that the convention has nothing to do with tail recursion, because both options are tail recursive. Tail recursion doesn't require that the recursive call be the last expression physically written in the function body. It requires it be the last expression evaluated before returning from the function, which is true in both cases. It's a moot point anyway in JavaScript, because to my knowledge, no commonly-used JavaScript engines do tail call elimination.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.