【クイズでわかる】JavaScriptの「~」って何?~indexOfや~~の役割と仕組みを理解する

こんにちは!Reiです‎(˵ •̀ ᴗ – ˵) ✧


突然ですが…、この記号、ちゃんと説明できますか?

~str.indexOf("apple")

コードの中で見かけて、「なんとなく動いてるけど、正直よくわかってない…」なんて状態になったことはありませんか?👀

見た目もちょっと独特で、一瞬「これ何してるの?」と手が止まりやすい書き方ですよね 💦


今回はクイズ形式で、チルダ ~ の動きや、indexOf() と一緒に使われていた理由、そして ~~ の使い方まで確認していきます!
1問目から「え、そうなるの?」ってなるかも…!?✨

考えながら、ひとつずつ見ていきましょう ᥫᩣ ̖́-


第1問 チルダ ~ を使うと?

まずはここから!

console.log(~1);
console.log(~-1);

この結果、どうなるでしょうか?👀

  1. 1 が -1 になって、-1 が 1 になる
  2. ~1 は -2~-1 は 0 になる
  3. エラーになる

正解は… (ここをクリック!)

→2の「~1 は -2~-1 は 0 になる」です!


解説 !!

~ は、ビット演算子のひとつで、 ビット反転をするための記号です。
ビット反転というのは、 2進数で見たときに 0 を 1 に、1 を 0 にひっくり返す処理のこと。

…と言われても、ちょっとピンとこないですよね 👀


ここで大事なのは、細かいビットの仕組みよりも結果としてどうなるかを押さえることということです!

JavaScript では、次のような関係になります↓

~n = -(n + 1)

つまり、

~1;   // -2
~-1;  // 0
~5;   // -6

とこのように、元の数とは違う形に変換されるのがポイントです 💡


まずは「チルダを付けると、元の数がそのまま反転するわけではない」 というところを押さえておいてください‎(˵ •̀ ᴗ – ˵) ✧


第2問 indexOf() にチルダをつけると?

次はこちら!

const str = "Hello Taro";

if (str.indexOf("Taro") !== -1) {
  console.log("見つかった!");
}

if (~str.indexOf("Taro")) {
  console.log("見つかった!");
}

この2つは、結果としてはどちらも同じ動きをします。 では、~ をつけることで、どんな変化が起きているのでしょうか?👀

  1. 検索処理が高速化される
  2. 戻り値が変換され、条件判定に利用しやすくなる
  3. 戻り値が論理値として評価される

正解は… (ここをクリック!)

→ 2の「-1 を 0 に変えて、条件式で扱いやすくできるから」です!


解説 !!

ここが ~indexOf() のいちばん大事なポイントです 👀

まず前提として、indexOf()見つからなかったときに -1 を返します。

"Hello".indexOf("x"); // -1

そして、第1問で見たとおり…、~-1 は 0 となります。


また、JavaScript では、条件式の中で

  • 0false
  • 0 以外の数値は true

として扱われます。

つまり、

~str.indexOf("Taro")

は、

  • 見つからない(-1)→ 0false
  • 見つかる(0以上)→ -1 や -2true

という動きになります。
見つからなかったときだけ false になるのがポイントです 💡


その結果、

if (~str.indexOf("Rei")) {
console.log("見つかった!");
}

と書くだけで、「含まれているかどうか」を判定できるようになります。


少しトリッキーな書き方ですが、短く書けることから、以前のコードでは使われることもありました。ただ、仕組みを知らないと少し読みづらいため、最近では ~(チルダ) を使った判定はあまり見かけなくなっています。


第3問 ~~ を使うとどうなる?

次はこちら!

console.log(~~4.9);
console.log(~~-4.9);

このコードを実行すると、どうなるでしょうか?

  1. 4 と -4 になる
  2. 5 と -5 になる
  3. 小数のまま変わらない

正解は… (ここをクリック!)

→ 1の「4 と -4 になる」です!


解説 !!

~~ は、チルダを2回続けて書くことで、値を 32bit 整数に変換するすることができます。


このとき、小数はどうなるかというと…、小数点以下が切り捨てられます。

~~4.9;   // 4
~~-4.9;  // -4

ここで少し注意ポイント 👀

「切り捨て」と聞くと、Math.floor() を思い浮かべるかもしれませんが、実はまったく同じではありません!

Math.floor(-4.9); // -5
~~-4.9; // -4

とこのように、 ~~ は 0 に向かって丸める(小数を削る)動きになります。

なので、どちらかというとMath.floor() ではなく、Math.trunc() に近い挙動になります。


少しテクニカルな書き方ですが、短く書けることから使われることもありました。

ただし、意図が伝わりづらいため、今のコードでは Math.trunc() などを使うのがおすすめです。


第4問 今なら何を使うべき?

最後の問題はこちら!

const str = "Hello Taro";

if (str.???) {
  console.log("見つかった!");
}

現在の JavaScript で、 「文字列が含まれているか」を判定したいとき、 どの書き方がよいでしょうか?

  1. includes("Taro")
  2. indexOf("Taro") + 1
  3. ~indexOf("Taro")

正解は… (ここをクリック!)

→ 1の includes("Taro") です!


解説 !!

現在の JavaScript では、文字列に特定の文字が含まれているかを調べるときは includes() を使うことが多いです。

includes() は、戻り値が true / false ではっきりしているため、条件式としてそのまま使えます。


なので、

const str = "Hello Taro";
if (str.includes("Taro")) {
console.log("見つかった!");
}

のような書き方で、「含まれているかどうかを判定している」ことがそのままコードに表すことができるのです。


一方、indexOf() を使った書き方自体は間違いではないのですが、

str.indexOf("Taro") !== -1

と書く必要があったり、

~str.indexOf("Taro")

のように ~(チルダ) の仕組みを知らないと「何をしているのか」が少し伝わりにくくなります。


そのため、コードを見たときに意図が伝わりやすい書き方が選ばれることが多く、~(チルダ) を使った判定はあまり見かけなくなっています。


ここまでのポイントおさらい !!

今回の内容をまとめると、次のとおり↓

チルダ ~
・ビット反転をするための演算子
・結果は ~n = -(n + 1) と考えると理解しやすい
・見た目と直感がズレやすいので使用時は注意


~indexOf()
indexOf() は見つからないと -1 を返す
~-1 は 0 になる
・この性質を使って、見つからないときだけ false 扱いにできる


~~
・値を整数寄りの形にしたいときに使われた書き方
・小数点以下が切り落とされる
Math.floor() と完全に同じではないので注意が必要


~ や ~~ は見た目のインパクトが強く、最近ではあまり使われる場面が少なく、役割がわかりづらく感じやすい部分でもあります。

「見かけたときに意味がわかる」状態にしておきましょう


最後に

~~~ は、最近では見かけないので見落ちしがちだけど、コードの中に出てくると戸惑いやすい記号のひとつ。

ただ、仕組みを知っていると、やっていることは意外とシンプルなんですよね。


~indexOf() のように、シンプルな仕組みを組み合わせて処理を成り立たせているのを見ると、発想の面白さを感じます 👀


こういう書き方を見かけたときに「読める」だけでなく、自分でもサッと組み合わせて使えるようになりたいですね ᥫᩣ ̖́-

コメント

タイトルとURLをコピーしました