Rename snippets with potential naming conflicts
This commit is contained in:
68
snippets/articles/s/javascript-generator-for-range.md
Normal file
68
snippets/articles/s/javascript-generator-for-range.md
Normal file
@ -0,0 +1,68 @@
|
||||
---
|
||||
title: Using JavaScript generator functions for ranges
|
||||
shortTitle: Generator functions for ranges
|
||||
type: story
|
||||
language: javascript
|
||||
tags: [function,array]
|
||||
author: chalarangelo
|
||||
cover: generator
|
||||
excerpt: Learn how to use JavaScript ES6 generators and iterators to iterate over ranges of numbers.
|
||||
dateModified: 2021-06-12T19:30:41+03:00
|
||||
---
|
||||
|
||||
### Generator functions
|
||||
|
||||
[JavaScript ES6 generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*) allow you to define functions that can be exited and later re-entered, while retaining their context (variable bindings). They are defined using `function*` (`function` keyword followed by an asterisk) and use `yield` expressions to return their result. For example:
|
||||
|
||||
```js
|
||||
function* generateRange(end, start = 0, step = 1) {
|
||||
let x = start - step;
|
||||
while(x < end - step) yield x += step;
|
||||
}
|
||||
|
||||
const gen5 = generateRange(5);
|
||||
let x = gen5.next();
|
||||
|
||||
while (!x.done) {
|
||||
console.log(x.value);
|
||||
x = gen5.next();
|
||||
} // Logs: 0, 1, 2, 3, 4
|
||||
```
|
||||
|
||||
In the above example, we define a generator function, `generateRange`, which will return each value between `start` and `end`, incrementing by `step` each time. We use the [generator object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator) to call `Generator.prototype.next()` until it returns `{value: undefined, done: true}` to iterate over the values the generator produces.
|
||||
|
||||
### Symbol.iterator
|
||||
|
||||
[`Symbol.iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/iterator) specifies the default iterator for an object. Oftentimes, `Symbol.iterator` is implemented using a generator function. For example:
|
||||
|
||||
```js
|
||||
const iterableXx = {
|
||||
[Symbol.iterator]: function* () {
|
||||
yield 1;
|
||||
yield 2;
|
||||
}
|
||||
};
|
||||
|
||||
console.log([...iterableX]); // [1, 2]
|
||||
```
|
||||
|
||||
As you can see in this example, the object is made iterable by assigning a generator function to its `Symbol.iterator` property. This can come especially handy, if you want to iterate over some arbitrary data or create an object that is iterable and uses a generator function under the hood.
|
||||
|
||||
### Putting it all together
|
||||
|
||||
Knowing how both concepts work, we can combine them to create a range generator, similar to Python or Ruby's ranges:
|
||||
|
||||
```js
|
||||
const range = (end, start = 0, step = 1) => {
|
||||
function* generateRange() {
|
||||
let x = start - step;
|
||||
while(x < end - step) yield x += step;
|
||||
}
|
||||
return {
|
||||
[Symbol.iterator]: generateRange
|
||||
};
|
||||
}
|
||||
|
||||
console.log([...range(7)]); // [0, 1, 2, 3, 4, 5, 6]
|
||||
for (let i of range(8, 2, 2)) console.log(i); // Logs: 2, 4, 6
|
||||
```
|
||||
Reference in New Issue
Block a user