HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptMinor

Handling arguments in a Python-like range() function in JavaScript

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
handlingargumentsjavascriptrangefunctionlikepython

Problem

I'm making a Python-like range() function (see Python docs) using JavaScript. This function can take from 1 to 3 arguments. There are 3 variables (start, stop and step) that need to have some value, either from arguments, or a default value.

  • If only one argument is passed, start is 0, stop is the first argument and step is 1.



  • If two arguments are passed, start is the first argument, stop is the second argument and step is 1.



  • If three arguments are passed, start is the first argument, stop is the second argument and step is the third argument.



I'm aware that since ECMAScript 6 JavaScript has default parameters, but the situation here is more complex. Therefore, I used rest parameters to get an array of all arguments and then assign them to appropriate variables.

const range = (...args) => {
  if (args.length  3) {
    throw new Error('This function takes between 1 and 3 arguments')
  }
  const [start, stop, step] = {
    1: [0, ...args, 1]
   ,2: [...args, 1]
   ,3: args
  }[args.length]
}


I'm using the solution presented in the article Replacing switch statements with Object literals. The object keys are numbers of arguments and values are arrays with values for start, stop and step. I select the array which matches args.length and use destructuring assignment to assign the array elements respectively to start, stop and step.

This code is quite short, but I'm not sure whether it's readable. I came up with an alternative solution, using simple if-else blocks. I have to declare the variables at the beginning here, because let and const are block-scoped, so declaring them inside the if-else blocks would have no effect on the rest of the function.

```
const range = (...args) => {
let [start, stop, step]
if (args.length === 1) {
;[start, stop, step] = [0, ...args, 1]
} else if (args.length === 2) {
;[start, stop, step] = [...args, 1]
} else if (args.length === 3) {
;[start, st

Solution

I like the edited version. I'd suggest just one small change:

const range = (...args) => {
  if (args.length  3) {
    throw new Error('This function takes between 1 and 3 arguments')
  }
  let [start, stop, step = 1] = args
  ;[start, stop] = (stop === undefined) ? [0, start] : [start, stop]
}


Aside from reducing the visual clutter of the if statement, in general I find that expressions (which always execute) are easier to reason about than branching statements, even though the resulting logic is the same.

Code Snippets

const range = (...args) => {
  if (args.length < 1 || args.length > 3) {
    throw new Error('This function takes between 1 and 3 arguments')
  }
  let [start, stop, step = 1] = args
  ;[start, stop] = (stop === undefined) ? [0, start] : [start, stop]
}

Context

StackExchange Code Review Q#145472, answer score: 2

Revisions (0)

No revisions yet.