DEV Community

JS Bits Bill
JS Bits Bill

Posted on • Edited on

Symbols Are Your Friend Series Part VII: Symbol.asyncIterator, Symbol.hasInstance & Symbol.isConcatSpreadable

Symbols Are Your Friend Series


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

  • Symbol.asyncIterator
  • Symbol.hasInstance
  • Symbol.isConcatSpreadable

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

// 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);
  }
})();
Enter fullscreen mode Exit fullscreen mode

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


Symbol.hasInstance
This symbol is used to determine whether or not a constructor has an instance of another object when instanceof is used.

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

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
Enter fullscreen mode Exit fullscreen mode

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

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

pokemon.concat(transformers);
// Returns ["Eevee", "Snorlax", "Ditto", "Jazz", "Grimlock", "Arcee"]
Enter fullscreen mode Exit fullscreen mode
const pokemon = ['Eevee', 'Snorlax', 'Ditto'];
const transformers = ['Jazz', 'Grimlock', 'Arcee'];

transformers[Symbol.isConcatSpreadable] = false;

pokemon.concat(transformers);
// Returns ["Eevee", "Snorlax", "Ditto", Array(3)]
Enter fullscreen mode Exit fullscreen mode

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

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"]
Enter fullscreen mode Exit fullscreen mode

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


Check out more #JSBits at my blog, jsbits-yo.com. Or follow me on Twitter.

Top comments (0)