4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Symbol.split とは何か ざっくり【JavaScript】

Posted at

シンボルとは

  • 定数みたいなもの
  • 他のシンボルと等値比較できて、他のどのシンボルとも異なる(ユニークである)
  • オブジェクトのキーにできる
  • 一旦、ユニークな文字列だと思ってもらっても良い
const symbol1 = Symbol();  // シンボルを作成
const symbol2 = Symbol();  // 別のシンボルを作成

console.log(symbol1 === symbol2);  // => false

const a = {};
a[symbol1] = 10;
a[symbol2] = 20;

console.log(a);           // => {Symbol(): 10, Symbol(): 20}
console.log(a[symbol1]);  // => 10
console.log(a[symbol2]);  // => 20

Symbol.split とは

  • JavaScript に存在する定数
  • これ単体ではあまり意味がない
a[Symbol.split] = 30;

console.log(a);                // => {Symbol(): 10, Symbol(): 20, Symbol(Symbol.split): 30}
console.log(a[Symbol.split]);  // => 30

正規表現オブジェクトの Symbol.split メソッドとは

  • 正規表現オブジェクトは Symbol.split をキーとする項目を持つ
    • これは関数オブジェクト
    • 正確には正規表現のプロトタイプが持っている
const regexp = /[xyz]+/;
console.log(regexp[Symbol.split]);  // => ƒ [Symbol.split]() { [native code] }

その関数は 2 つの引数を取り、配列を返す

RegExp.prototype[Symbol.split]() は 2 つの引数を取る関数になっている

const regexp = /[xyz]+/;

// 引数は 2 個
console.log(regexp[Symbol.split].length);  // => 2

// 最初の引数は split 対象の文字列
console.log(regexp[Symbol.split]("123xyz456zyx789"));  // => ['123', '456', '789']

「Symbol.split メソッドを持つオブジェクト」とは

  • オブジェクトであって、
  • かつ Symbol.split をキーとするメソッドを持つもの

つまり、こういうオブジェクトです。

const obj = {};
obj[Symbol.split] = () => "Hey! Listen!";

// またはこのようにも書ける
// const obj = {
//     [Symbol.split]: () => "Hey! Listen!",
// };

console.log(typeof(obj));        // => object
console.log(obj[Symbol.split]);  // => () => "Hey! Listen!"

つまり、 String.prototype.split() の引数に Symbol.split メソッドを持つオブジェクト を指定するということは、こういうことになります。

const obj = {};
obj[Symbol.split] = () => "Hey! Listen!";
"abc123".split(obj);  // => 'Hey! Listen!'

separator
各分割がどこで行われるかを表すパターンです。undefined、文字列、または Symbol.split メソッドを持つオブジェクトを指定することができます。典型的な例は正規表現です。

まとめ

  • Symbol.split というシンボルが JavaScript に存在する
  • String.prototype.split() の引数に Symbol.split メソッドを持つオブジェクト を指定することができる
  • 正規表現オブジェクトは Symbol.split メソッドを持つ
    • console.log((/[xyz]+/)[Symbol.split]); // => 関数オブジェクト
  • つまり、String.prototype.split() の引数に正規表現オブジェクトを指定することができる
  • Symbol.split は、正規表現オブジェクト等にこの関数を備えるためのオブジェクトのキー

余談(なぜシンボルは文字列ではないのか)

  • シンボルを Symbol という名前空間に定義することで、既存のコードを破壊せずに済む
  • もし正規表現オブジェクトに ES6 側で split というプロパティを生やしてしまうと、既存のコードが壊れてしまう
    • このため、シンボルは文字列とは異なるものである必要がある
const regex = /[xyz]+/;

// もしシンボルと文字列が同じなら、以下の ES6 以前のコードが壊れる
regex["split"] = "Hello";
console.log(regex["split"]);  // => Hello

// シンボルは他のどのシンボルとも異なるため、この ES6 以前のコードは壊れない
const Symbol = { split: "myKey" };
regex[Symbol.split] = "World";
console.log(regex[Symbol.split]);  // => World
  • また、 for ... in などの挙動が壊れないように、シンボルがキーの項目は列挙されないようになっている
const a = {
    foo: 10,         // キーが文字列
    [Symbol()]: 20,  // キーがシンボル
}

for (const x in a) {
    console.log(x);  // foo だけ列挙される
}
  • このように、互換性の都合が大きいため、一般 Web 開発ユーザーにとっては Symbol を使う機会はほとんどないかもしれない

感想

JavaScript のプロトタイプには、特別なシンボルをキーに持つインスタンスメソッドや静的プロパティがたくさんあるようです。勉強になりました。

  • Symbol.asyncIterator
  • Symbol.hasInstance
  • Symbol.isConcatSpreadable
  • Symbol.iterator
  • Symbol.match
  • Symbol.matchAll
  • Symbol.replace
  • Symbol.search
  • Symbol.species
  • Symbol.split
  • Symbol.toPrimitive
  • Symbol.toStringTag
  • Symbol.unscopables

4
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?