Symbols Are Your Friend Series Part VII: Symbol.asyncIterator, Symbol.hasInstance & Symbol.isConcatSpreadable
Tags: javascript
Published: 2020-11-20 00:08:39

<b>Symbols Are Your Friend Series</b>
  - [Part I: A Gentle Introduction](https://dev.to/js_bits_bill/symbols-are-your-friend-a-gentle-introduction-js-bits-23af)
  - [Part II: Symbol.for() & Symbol.keyFor()](https://dev.to/js_bits_bill/symbols-are-your-friend-part-ii-symbol-for-symbol-keyfor-js-bits-3clc)
  - [Part III: Symbol.iterator](https://dev.to/js_bits_bill/symbols-are-your-friend-part-iii-symbol-iterator-js-bits-18c4)
  - [Part IV: Symbol.search, Symbol.split, & Symbol.species](https://dev.to/js_bits_bill/symbols-are-your-friend-part-iv-symbol-search-symbol-split-symbol-species-js-bits-4i25)
  - [Part V: Symbol.toPrimitive, Symbol.toStringTag, & Symbol.unscopables](https://dev.to/js_bits_bill/symbols-are-your-friend-part-v-symbol-toprimitive-symbol-tostringtag-symbol-unscopables-js-bits-nee)
  - [Part VI: Symbol.match, Symbol.matchAll & Symbol.replace](https://dev.to/js_bits_bill/symbols-are-your-friend-series-part-vi-symbol-match-symbol-matchall-symbol-replace-js-bits-539g)

---

This is it - the last of the well-known symbols! Today we'll look at:

<ul>
  <li><code>Symbol.asyncIterator</code></li>
  <li><code>Symbol.hasInstance</code></li>
  <li><code>Symbol.isConcatSpreadable</code></li>
</ul>

---

<b><code>Symbol.asyncIterator</code></b>
Similar to <code>Symbol.iterator</code>, <code>Symbol.asyncIterator</code> functions the same way, except they return promises. This enables us to make an object that has asynchronous functionality iterable:

```js
// Create iterable object
const todos = {
  [Symbol.asyncIterator]: function() {
    let i = 1;
    const limit = 4;

    return {
      async next() {
        if (i === limit) return { done: true };

        i++;
        return { value: await fetchTodo(i), done: false }
      }
    }
  },
};

// Fetch a todo object
async function fetchTodo(num) {
  const url = `https://jsonplaceholder.typicode.com/todos/${num}`;
  const response = await fetch(url);
  return await response.json();
}

// Asynchronously iterate through todos
(async () => {
  for await (const todo of todos) {
    console.log(todo.title);
  }
})();
```

With this example, we're effective making our <code>todos</code> object async iterable. <code>Symbol.asyncIterator</code> is also commonly implemented with generator functions but we'll explore those in another article.

---
<b><code>Symbol.hasInstance</code></b>
This symbol is used to determine whether or not a constructor has an instance of another object when <code>instanceof</code> is used.

This allows us to customize the behavior of <code>instanceof</code> when it operates on our constructor object:

```js
class PowerRanger {
  constructor(name) {
    this.name = name;
  }
  
  static [Symbol.hasInstance](instance) {
    const rangersRegEx = /jason|zack|kim|billy|trini/i;
    return rangersRegEx.test(instance.name);
  }
}

const jason = new PowerRanger('Jason');
const bob = new PowerRanger('Bob');

jason instanceof PowerRanger; // true
bob instanceof PowerRanger; // false
```
---

<b><code>Symbol.isConcatSpreadable</code></b>
This symbol is a toggle that indicates if an object should be flatted when <code>Array.prototype.concat()</code> is used:

```js
const pokemon = ['Eevee', 'Snorlax', 'Ditto'];
const transformers = ['Jazz', 'Grimlock', 'Arcee'];

pokemon.concat(transformers);
// Returns ["Eevee", "Snorlax", "Ditto", "Jazz", "Grimlock", "Arcee"]
```

```js
const pokemon = ['Eevee', 'Snorlax', 'Ditto'];
const transformers = ['Jazz', 'Grimlock', 'Arcee'];

transformers[Symbol.isConcatSpreadable] = false;

pokemon.concat(transformers);
// Returns ["Eevee", "Snorlax", "Ditto", Array(3)]
```

A great use for this Symbol is to force normally unflattenable array-like objects to flatten:

```js
const pokemon = ['Eevee', 'Snorlax', 'Ditto'];
const transformers = {
  [Symbol.isConcatSpreadable]: true, 
  length: 3, // Length needed to specify # of props to add
  0: 'Jazz', 
  1: 'Grimlock',
  2: 'Arcee'
};

pokemon.concat(transformers);
// Returns ["Eevee", "Snorlax", "Ditto", "Jazz", "Grimlock", "Arcee"]
```
---

This concludes the <b>Symbols Are Your Friend</b> series! We've just gone from Symbol zero to hero! 🦸

----------
Check out more #JSBits at my blog, [jsbits-yo.com](http://jsbits-yo.com/). Or follow me on [Twitter](https://twitter.com/JS_Bits_Bill).