Hemanth's Scribes

javascript

Well-known Symbols

Author Photo

Hemanth HM

Thumbnail

I was recently asking on public forums if people can name at least three Well-known Symbols in JavaScript without looking up and few could. Let’s explore these powerful tools!

Symbol.isConcatSpreadable

This symbol is used to determine if an object should be flattened when concatenated with other objects. It can be used to change the behavior of the Array.prototype.concat method.

const arr1 = [1, 2, 3];
const spreadable = {
  [Symbol.isConcatSpreadable]: true,
  0: 4,
  1: 5,
  2: 6,
  length: 3
};

console.log([].concat(arr1, spreadable)); // [1, 2, 3, 4, 5, 6]

Symbol.species

This symbol is used to specify the constructor to use when creating derived objects. It can be used to customize the behavior of built-in methods that create new objects.

class MyArray extends Array {
  static get [Symbol.species]() {
    return Array;
  }
}

const myArray = new MyArray(1, 2, 3);
const mappedArray = myArray.map(x => x * 2);

console.log(mappedArray instanceof MyArray); // false
console.log(mappedArray instanceof Array);   // true

P.S: this functionality may be removed in the future.

Symbol.match

This symbol is used to determine the value to search for when using the String.prototype.match method. It can be used to change the behavior of the match method for RegExp-like objects.

const myRegex = /test/;
'/test/'.startsWith(myRegex); // Throws TypeError

const re = /foo/;
re[Symbol.match] = false;

"/foo/".startsWith(re); // true
"/bar/".endsWith(re);   // false

P.S: The presence of that symbol is what marks an object as “being a regex”.

const myRegex = /foo/g;
const str = 'How many foos in the the foo foo bar?';

for (result of myRegex[Symbol.matchAll](str)) {
  console.log(result); // we will get the matches
}

Symbol.replace

This symbol is used to determine the replacement value when using the String.prototype.replace method. It can be used to change the behavior of the replace method for RegExp-like objects.

const customReplace = str => str.replace(/\d+/g, match => `-${match}-`);

const customString = {
  [Symbol.replace]: customReplace
};

const originalString = "foo123bar456baz";
const result = originalString.replace(customString, '*');

console.log(result); // outputs "foo-123-bar-456-baz"

Symbol.search

This symbol is used to determine the value to search for when using the String.prototype.search method. It can be used to change the behavior of the search method for RegExp-like objects.

const customSearch = str => str.search(/\d+/);

const customRegExp = {
  [Symbol.search]: customSearch
};

const string = "foo123bar456baz";
string.search(customRegExp); // outputs 3

Symbol.split

This symbol is used to determine the value to split when using the String.prototype.split method. It can be used to change the behavior of the split method for RegExp-like objects.

const customSplit = str => str.split(/\d+/);

const customRegExp = {
  [Symbol.split]: customSplit
};

const string = "foo123bar456baz";
string.split(customRegExp); // outputs [ 'foo', 'bar', 'baz' ]

Symbol.unscopables

This symbol is used to determine the properties of an object that should be excluded from the scope of with statements. It can be used to change the behavior of with statements.

const person = {
  age: 42
};

person[Symbol.unscopables] = {
  age: true
};

with (person) {
  console.log(age);
  // Expected output: Error: age is not defined
}

Symbol.dispose

Explicit Resource Management refers to a system in which the user manages the lifespan of a “resource” explicitly, either by using imperative methods (such as Symbol.dispose) or declarative methods (such as using a block-scoped declaration).

{
  console.log(1);
  using {
    [Symbol.dispose]() {
      console.log(2);
    }
  };
  console.log(3);
}
// will log 1, 3, 2

This informational blog aimed to impart a deeper understanding of the well-known symbols intrinsic to the JavaScript language. These symbols, such as Symbol.iterator, Symbol.toStringTag, and Symbol.for, represent sophisticated and versatile instruments that can be utilized to augment and regulate the behavior of code.

Acquiring a comprehensive understanding of the available symbols within the JavaScript environment is crucial in the development of high-performing, maintainable, and scalable applications. Hence, it is recommended that during the conceptualization and implementation phase of a project, one evaluates the feasibility of incorporating these symbols, to streamline the code and achieve desired outcomes in a more sophisticated and elegant manner.

Thanks to @ljharb for a quick review on this post.

#javascript#symbols#es6
Author Photo

About Hemanth HM

Hemanth HM is a Sr. Machine Learning Manager at PayPal, Google Developer Expert, TC39 delegate, FOSS advocate, and community leader with a passion for programming, AI, and open-source contributions.