JS Bits with Bill
JS Bits with Bill

JS Bits with Bill

Symbols Are Your Friend Series Part VI: Symbol.match, Symbol.matchAll & Symbol.replace

Symbols Are Your Friend Series Part VI: Symbol.match, Symbol.matchAll & Symbol.replace

JS Bits with Bill's photo
JS Bits with Bill

Published on Nov 10, 2020

3 min read

Symbols Are Your Friend Series


Well, we've made it this far 😅. We might as well explore the remaining Symbol properties. There's only 6 more left, but we'll break them up into 2 more articles. Today we'll look at:

  • Symbol.match
  • Symbol.matchAll
  • Symbol.replace

Symbol.match This symbol defines the matching behavior of a regular expression against a string. Here are 2 interesting ways this can be used:

The first way allows us to override the internal check within certain String methods (like .startsWith(), .includes(), etc.) that check if the first argument is erroneously an regular expression. This internal check uses the match property so if we simple set it to false we can make our regex act as if it's not a regex and use those String methods:

const myRegex = /abc/;
'/abc/'.startsWith(myRegex); // Throws error

// Override myRegex to not be treated as a regular expression
myRegex[Symbol.match] = false;
'/abc/'.startsWith(myRegex); // true

The other way we can use Symbol.match is similar to some of the other well-known symbols we've seen already like Symbol.split:

const myRegex = /abc/;
myRegex[Symbol.match] = function(string) {
  const index = string.search(this);
  if (index > -1) return `Match found @ index ${index}`;
  return 'No match found';
};

'I know my 123\'s'.match(myRegex); // Returns "No match found"

Symbol.matchAll This symbol is a method that returns an iterator of results when you match a regular expression against a string. Before we check this out, note that there's already a String.prototype.matchAll() method that does the inverse: it matches a string against a regular expression:

const myRegex = /wood/g;
const str = 'How much wood would a woodchuck chuck?';

for (result of str.matchAll(myRegex)) {
  console.log(result);  // Logs matches
}

So with Symbol.matchAll we can essentially swap the calling object and argument types:

const myRegex = /wood/g;
const str = 'How much wood would a woodchuck chuck?';

for (result of myRegex[Symbol.matchAll](str)) {
  console.log(result); // Logs matches
}

RegExp.matchAll() would otherwise throw a TypeError.


Symbol.replace This symbol defines the behavior for the .replace() method on a string.

Default behavior:

const spoonRegex = /spoon/;

const result = 'There is no spoon'.replace(spoonRegex, 'fork');
console.log(result); // Logs "There is no fork"

Symbol.replace modification:

const spoonRegex = /spoon/;
spoonRegex[Symbol.replace] = function(string, replacement) {
  const match = string.match(this) || [];
  const index = match.index;

  if (!match.length) return string;
  return `${string.slice(0, index)}${replacement}, lol`;
};

const result = 'There is no spoon'.replace(spoonRegex, 'fork');
console.log(result); // Logs "There is no fork, lol"

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

 
Share this