【JavaScript】文字列中に文字列が含まれているかを検査する

 JavaであればString#containsが使えますが、JavaScriptではどのような方法があるのでしょうか。

解決方法

 それでは、現代における解決方法を、推奨する順にご紹介します。

String#includesを使う

 文字列”The quick brown fox jumps over the lazy dog”に、”dog”が含まれているかを調べたい場合、以下のようにプログラミングするのが最も好ましい方法です。

const str = "The quick brown fox jumps over the lazy dog";
const partial = "dog";
console.log(str.includes(partial));  // -> true

 何も問題がなければ、こちらを利用することをお勧めします。

 しかし、上記に挙げたincludesは、ES6から実装された比較的新しいメソッドです。つまり、特定のブラウザで実装されていない可能性があり、そのことに十分留意する必要があります。

 昨今の事情を勘案すれば、Babelなどのトランスパイラを利用して、より簡潔な書き方でコードを書いていくほうが良いことは間違いありませんが、トランスパイラを使えない事情がある場合もあるでしょう。

 その場合、MDN String.prototype.includes()にも記載がありますが、includesメソッドをエミュレートするコードを入れることもできます。

if (!String.prototype.includes) {
  String.prototype.includes = function(search, start) {
    'use strict';
    if (typeof start !== 'number') {
      start = 0;
    }

    if (start + search.length > this.length) {
      return false;
    } else {
      return this.indexOf(search, start) !== -1;
    }
  };
}

 これを先頭で呼んでやれば、レガシーブラウザでも問題なく動きます。

String#indexOfを使う

 しかし、プロジェクトの意向によってはそれすら許されない場合もあるかもしれません。その場合には、古来より伝わるindexOfを使った判定を行うことができます。

var str = "The quick brown fox jumps over the lazy dog";
var partial = "dog";
console.log(!!~str.indexOf(partial));  // -> true

 これなら、古いブラウザでも問題なく動きます。

 ところで、先ほど挙げたソースコードの中で、!!と~というふたつの妙な記号が出てきました。

 !は、反転演算子です。他の型をbooleanにキャストする場合によく使います。

!false // -> true
!!false // -> false
!!!false // -> true

!"" // -> true
!!"" // -> false

!0 // -> true
!!0 // -> false

 ~は、ビット反転演算子です。符号ありの2進数を全ビットに対し無条件で反転します。

 符号あり2進数で-1は11111111です。(8bitの場合)これを反転すると00000000、即ち0になります。この特性を利用して、indexOfが-1の場合は0に変換しています。

 JavaScriptでは、0はfalse、そのほかはtrueとして評価されます。以下は同じ結果を返します。

console.log("abcde".indexOf("cd") !== -1);  // -> true
console.log(!!~"abcde".indexOf("cd"));     // -> true

 しかし特殊な記法には変わりないので、コメントなどで補足することも重要です。

まとめ

 JavaScriptは、特に進化の早い言語です。毎年のように新しいメソッドや構文が多数追加されているので、常にアンテナを張って、より優れた書き方をしたいものですね。