Using Python range() in JavaScript

What is the Python range() type?
If you’re not familiar with Python, range() refers to the use of the range type to create an immutable sequence of numbers.

“The range type represents an immutable sequence of numbers and is commonly used for looping a specific number of times in for loops.” — docs.python.org

The range() constructor has two forms of definition:
range(stop)
range(start, stop[, step])
A concise explanation of the parameters, return value, etc. can be found on programiz.
A few examples:
>>> list(range(10))
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> list(range(0, 30, 5))
[0, 5, 10, 15, 20, 25]
>>> list(range(0, 10, 3))
[0, 3, 6, 9]
>>> list(range(0, -10, -1))
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
>>> list(range(0))
[]
>>> list(range(1, 0))
[]
view raw range.py hosted with ❤ by GitHub
Building the range() function in JavaScript
For simplicity sake, we will ignore the optional step argument.
By using the Array constructor, fill and map, you could work out a simple solution in a quick one-liner:
new Array(stop - start).fill(start).map((el, i) => el + i)
And maybe then offer a more complete solution, covering the case of calling range with only one argument:
function range(start, stop) {
// setting up default values for start and stop
// calling range(i) is equal to calling range(0, i)
if (stop === undefined) {
stop = start;
start = 0;
}
if (start > stop)
return [];
return new Array(stop - start).fill(start).map((el, i) => el + i);
}
view raw range.js hosted with ❤ by GitHub
But it’s not quite it yet. Can you see why this solution is wrong?
Remember, calling Python range returns an immutable sequence of numbers. Notice how in order to get the familiar list data structure, the Python examples above wrap the return value of range with list().
An equal example in JavaScript should probably look something like this:
> Array.from(range(1, 11))
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
So how can we make a function in JavaScript return an “immutable sequence of numbers”? Is there any way to achieve the same structure of the range() return value in JavaScript?
Iterators to the rescue!
Iterators are wildly used in different programming languages to allow us to iterate over different data structures.

“In JavaScript an iterator is an object which defines a sequence and potentially a return value upon its termination.” —developer.mozilla.org

Specifically in JavaScript, an iterator is any object which implements the Iterator protocol by having a next() method that returns an object with two properties:
next() {
  ...
  return {
    value: // current value to be passed
    done: // did we finish iterating over the data structure?
  }
}
Using an iterator, you can provide your own logic on how to iterate. For example, here is a simple iterator that will skip every second item:
function makeSkipIterator(array, skip = 1) {
let i = null;
const iterator = {
next() {
i = i == null ? 0 : i + skip + 1;
if (i < array.length) {
return {
value: array[i],
done: false,
};
}
return {
value: "Done! 👋",
done: true,
};
},
};
return iterator;
}
const skipIterator = makeSkipIterator([1, 2, 3, 4, 5, 6, 7], 2);
console.log(skipIterator.next()); // { value: 1, done: false }
console.log(skipIterator.next()); // { value: 4, done: false }
console.log(skipIterator.next()); // { value: 7, done: false }
console.log(skipIterator.next()); // { value: "Done! 👋", done: true }
More importantly, If we create an object that defines [Symbol.iterator] which returns that iterator, we can get exactly the behavior we were looking for:
console.log(
Array.from({
[Symbol.iterator]: () => makeSkipIterator(["🐶", "🐱", "🐭", "🐹"], 2),
})
); // [ '🐶', '🐹' ]
Play around with these examples and see what kind of interesting and useful iterators you can create 💪.
By now you can probably imagine how we might approach creating Python range() in JavaScript. This is how I implemented it:
function range(start, stop) {
return {
[Symbol.iterator]() {
if (stop === undefined) {
stop = start;
start = 0;
}
let i = start - 1;
return {
next() {
i++;
if (i < stop) {
return {
value: i,
done: false,
};
}
return {
value: undefined,
done: true,
};
},
};
},
};
}
for (const i of range(3, 7))
console.log(i); // 3 4 5 6
view raw range.js hosted with ❤ by GitHub
As I mentioned, for simplicity's sake this implementation leaves out the step argument from the original Python range(), but it’s just a matter of extra logic that you can implement yourself. Feel free to @ me your solution ✌️.

32

This website collects cookies to deliver better user experience

Using Python range() in JavaScript