Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Implementing ranges in JavaScript
Antonio Villagra De La Cruz
Antonio Villagra De La Cruz

Posted on • Edited on • Originally published atantoniovdlc.me

     

Implementing ranges in JavaScript

Ranges are natively supported by a few (popular) programming languages. They allow for iteration over a defined space, while not have a linear increase in their memory footprint (all ranges always store a similar amount of data).

Let's try adding a similar idiom to JavaScript!


One way to approach this challenge is to write a plugin for a transpiler (for example a babel plugin) that would allow the following syntax:

constrange=(0..5)for(letiofrange){console.log(i)// 0, 1, 2, 3, 4}
Enter fullscreen modeExit fullscreen mode

Instead, we will provide a similar functionality with vanilla JavaScript.

for(letiofrange(0,5)){console.log(i)// 0, 1, 2, 3, 4}
Enter fullscreen modeExit fullscreen mode

We does the range stop at4 instead of5? This is a design choice, and as most languages that have a built-inrange as not inclusive of their last value, therange utility that we will build will follow a similar convention by default.

The above syntax also allows us to pass a third argument to the function to control thestep in between each iteration:

for(letiofrange(0,10,2)){console.log(i)// 0, 2, 4, 6, 8}
Enter fullscreen modeExit fullscreen mode

To start, let's create a classRange which will host the data needed for a range:

classRange{constructor(start,stop,step=1){this._start=Number(start);this._stop=Number(stop);this._step=Number(step);// Initialise a counter for iterationthis.i=Number(start);}first(){returnthis._start;}last(){returnthis._stop;}step(){returnthis._step;}}
Enter fullscreen modeExit fullscreen mode

We can now create a very basic (and not very useful) range:

constrange=newRange(0,10);range.first();// 0range.last();// 10range.step();// 1 (by default)
Enter fullscreen modeExit fullscreen mode

One of the main reasons we want ranges though is to iterate over them ... so let's implementiteration protocols in ourRange class!

To do so, we need to implement anext() method, as well as a[Symbol.iterator] method.

classRange{constructor(start,stop,step=1){...// Initialise a counter for iterationthis.i=Number(start);}first(){...}last(){...}step(){...}next(){if(this.i<this._stop){constvalue=this.i;this.i+=this._step;return{value,done:false};}return{value:undefined,done:true};}[Symbol.iterator](){returnthis;}}
Enter fullscreen modeExit fullscreen mode

Great! Now we can use our ranges as follow:

constrange=newRange(0,5)for(letiofrange){console.log(i)// 0, 1, 2, 3, 4}
Enter fullscreen modeExit fullscreen mode

or

constrange=newRange(0,5)range.next()// { value: 0, done: false }range.next()// { value: 1, done: false }range.next()// { value: 2, done: false }range.next()// { value: 3, done: false }range.next()// { value: 4, done: false }range.next()// { value: undefined, done: true }
Enter fullscreen modeExit fullscreen mode

There is one issue with our current implementation though, and that is that the range is depleted after a single iteration. We cannot reuse the same range in multiple consecutive loops.

Luckily, there is a one line fix to support that:

classRange{constructor(start,stop,step=1){...// Initialise a counter for iterationthis.i=Number(start);}first(){...}last(){...}step(){...}next(){if(this.i<this._stop){constvalue=this.i;this.i+=this._step;return{value,done:false};}// We reset the value once we have iterated over all values so that// ranges are reusable.this.i=this._start;return{value:undefined,done:true};}[Symbol.iterator](){returnthis;}}
Enter fullscreen modeExit fullscreen mode

Finally, to achieve the semantics we defined at the beginning, we need to wrap our class creation in a function:

classRange{...}functionrange(start,stop,step=1){returnnewRange(start,stop,step);}for(letiofrange(0,5)){console.log(i)// 0, 1, 2, 3, 4}
Enter fullscreen modeExit fullscreen mode

Again, inspired by this blog post, I decided to build a library with the aforementioned features and much more! Check it out:

GitHub logo AntonioVdlC / range

⛰ - Implement ranges in JavaScript

range

versionissuesdownloadslicense

Implement ranges in JavaScript.

Installation

This package is distributed via npm:

npm install @antoniovdlc/range

Motivation

Ranges are natively supported by a few (popular) programming languages. They allow for iteration over a defined space, while not having a linear increase in their memory footprint (all ranges always store a similar amount of data).

Usage

You can use this library either as an ES module or a CommonJS package:

importrangefrom"@antoniovdlc/range";
Enter fullscreen modeExit fullscreen mode

- or -

constrange=require("@antoniovdlc/range");
Enter fullscreen modeExit fullscreen mode

To create a range:

conststart=0;conststop=10;conststep=2;// Defaults to `1` if not passedconstinclusive=true;// Defaults to `false` if not passedconstr=range(start,stop,step,inclusive);
Enter fullscreen modeExit fullscreen mode

You can also pass an options object for convenience:

conststart=0;
Enter fullscreen modeExit fullscreen mode

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

  • Joined

More fromAntonio Villagra De La Cruz

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp