【JavaScript】「とりあえず」でjavascript:void(0)を使うな!!


まず初めに

最近よく、

<a href="javascript:void(0)" onclick="なんちゃらー">リンク</a>

というHTMLのコードを見かけるようになりました。
しかし、void関数の意味を理解せずに適当に使っている人が多く

<a href="javascript:void(0);alert('hogehoge');" onclick="~">リンク</a>

のような、全くもって意味の無い使い方をしている方も見受けられます。
なので、本記事ではvoid関数の仕組み、利用目的、利用方法などについて解説したいと思います

void関数ってなんぞや?

まず、void関数について説明したいと思います。
void関数は、引数に何を渡しても必ずundefinedを返す関数です。
説明は以上です。

、というのも、void関数は非常に単純な関数で、「真のundefined」を取得する事を目的に作られています。

いや真のundefinedってなんだよ

実は、古いJavaScriptエンジンのundefinedにはreadonly属性が付いておらず、自由に上書き可能なのです。

console.debug( undefined ); // undefined
let undefined = 1234;
console.debug( undefined ); // 古いjsエンジンだと、「1234」と表示される

これは困りましたね。。
「定義されていない」という事を表すundefinedを勝手に上書きされてしまったら、定義されていないかどうか判別するのにいちいちtypeof演算子を利用しないといけなくなってしまいます。
そこで登場したのがvoid関数です。
この関数は、undefinedでは無く、本当の意味での「真のundefined」を返してくれます。

でも何のためにaタグでJavaScriptURIを実行する際にvoid関数を使うんだよ

ここを理解していない方が多いみたいです。

javascript: から始まる URI をサポートしたブラウザに於いて、それは、URI 内のコードを評価し、戻り値が undefined でなければ、返された値にページコンテンツを置き換えます。void 演算子は、undefined を返すために使用できます。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/void

はい、こーいう事です。
つまり、aタグのリンク先がJavaScriptURIの時、その式がundefined以外を返した場合に、その内容をブラウザ上に表示するという仕様なのです。
具体的には、

<script>
function hogehoge() {
  // 何かの処理
  return "成功";
}
</script>
<a href="javascript:hogehoge();" onclick="alert('クリックされました!');">
  example
</a>

こんなコードがあった時に、IEなどの一部のブラウザでは「example」をクリックした際、アラートが表示された上でドキュメントが「成功」という2文字だけに置き換わってしまいます。その際、「example」のボタンなども全て削除されて上書きされます。

意味不明な仕様ですよね。
既に、ChromeなどのChromiumベースのブラウザでは廃止されました。
でも、今回は紹介出来ませんが、この仕様が役に立つ場合もあります。

誤用

冒頭でお見せした、このコード

<a href="javascript:void(0);alert('hogehoge');" onclick="~">リンク</a>

の何がダメなのか、お分かりになりましたでしょうか?

このaタグのhref先の式が実行された時に返される値は、最後のalert関数の戻り値の「true」です。

なので、JavaScriptURIに対応しているバージョンのIEでこのコードを実行すると、画面の左上に小さくtrueと表示されてしまいます。

では、どうすれば良いのか、、。
と言われましても、普通にundefinedを返せば良い話です。

おっと、NGワードを使ってしまいました。
NGワードとは、「普通に」です。

というのも、昔のJavaScriptエンジンではundefinedを上書き出来てしまうとお伝えした通り、undefinedが別の値に上書きされてしまっていたら、このコード

<a href="javascript:undefined" onclick="~">リンク</a>

はundefinedでは無く、その「別の値」を返してしまい、画面の左上に小さく何か表示されてしまいます。

なので、void関数は真のundefinedを返すためにあると考えれば、冒頭のコードは

<a href="javascript:void(alert('hogehoge'));" onclick="~">リンク</a>

このように直す事が出来るはずです。

最後に

正直、JavaScriptURIは今更使用するべきではありません。
というのも、XSSの脆弱性の原因になりやすいからです。
XSS対策で有名な、Content-Security-Policyヘッダーを利用したりすると、もはやJavaScriptURIは評価すらされなくなります。