JavaScriptに関するお知らせ

SINCE2019
>
【JS】voidのリンク無効化以外の使い道を考える

【JS】voidのリンク無効化以外の使い道を考える



こんにちは!ブログのモチベーションがvoidになる所だったMizutani(@sirycity)です。継続大事。

今日はJavaScriptに出てくるvoid演算子の使い方がリンク無効化以外にあるのか考えてみます。ちなみにTypeScriptのvoid型については特に取り扱わないので注意!まあvoid型は普通に使うからね。今回はいらない子のvoid演算子を頑張って輝かせる企画だから。許して。以後この記事ではvoid演算子をvoidと表記します。

結論

  • void、やっぱりいらない子だったよ...
  • voidのいい使い方とかでもググったけど見つからなかった...
  • でも頑張って使おうと思えば使えるケースもある。1つの式で一気に複数の関数を手軽に呼び出す時とか。
  • でもTypeScriptだと↑は使えない

そもそもvoidとは

voidはJavaScriptに出てくる演算子です。次の式をundefinedにします。こんな感じ。

void 42 // undefined
void(42) // undefined

const foo = void 42
foo === undefined // true
foo === 42 // false

簡単だね。何が来ようとundefinedになるだけ。ちなみにかっこは付けても付けなくてもok。void関数じゃなくてvoid演算子だからね。マイナスとかと一緒-3って書いても-(3)って書いても一緒みたいなもん。

voidの本来の?使い方

voidの本来の使い方はhtmlのaタグのhrefを無効化することでした。昔はね。ってかこれすら本来の使い方か微妙なんだけど。

aタグのhrefは書かれたURLに遷移するタグ。今更だね。こんな感じ。

<a href='https://www.google.com/'>
  Googleに移動
</a>

ところが、aタグは押しても何も起こらないボタンを作れなかったんです。hrefタグを空にすると自分自身に移動しちゃう。ぶっちゃけ謎仕様すぎて2020年の今こんな仕様作ったら世界中から総叩きされそうですが、まあ昔のwebは色々あったんだね。多分。

<a href=''>
  なぜか自分自身に移動
</a>

そこでvoidの出番。voidを使うことで不発ボタンができたってわけ。

<a href="javascript:void(0)" >
  押しても何も起こらない
</a>

そう、voidはれっきとした使い道があったんです。昔は。

時は2020年、void演算子は不発ボタンを作る役目を終えました。なぜならaタグにhrefが必須じゃなくなったから

<a>
  押しても何も起こらない
</a>

これでokです。元々voidを使った不発ボタンはchromeでリンク先が不適切に表示されてしまうといったUI面での欠点もあり、現在ではこれでaタグで作る不発ボタンの主流となってます。現在というか、2014年くらいから使えたんだけどね。

まあこのhref抜きの不発ボタンにも欠点はあるんですが(デフォルトのaタグのスタイルが外れるのでcssでcursor:pointerを設定しないといけないとか)そんなのはもう些細な問題です。

こうしてvoidはモダンフロントエンドの世界から葬り去られました

voidはもう輝けない

ぶっちゃけもう輝けません。実用的な使い道が出てくることはないでしょう...

ひょっとしたら自分が使い方知らないだけかも?とか思って、**「JavaScript void 使い道」**とかで調べたけど前述の不発ボタン以外の使い道が書いてあるものは何も出てこなかった。あと著名なJavaScriptライブラリをgrepしたりしたけど出てくるのはTSのvoid型ばかり。ダメだ。voidの時代は終わった。

voidをなんとかして輝かせたい

でも僕はvoidをなんっとかしてもう一度表舞台で輝かせたいんです。だってせっかくこの世に生まれてきたんだから。

1つの式で複数の関数を呼び出す

voidの特徴は必ず式がundefinedになること。必ずこれになる、ってのは昨今の関数型プログラミングにパラダイムがシフトしつつあるフロントエンドとも好相性なはず(要出典)。例えばこう。

const fn1 = () => true
const fn2 = () => true
const fn3 = () => false
const fn4 = () => true
const fn5 = () => false

fn1() // true
fn2() // true
fn3() // false
fn4() // true
fn5() // false

void fn1() // undefined
void fn2() // undefined
void fn3() // undefined
void fn4() // undefined
void fn5() // undefined

voidを用いることで明らかに挙動の予測がしやすくなっています。でもこれだけだと別に?って感じだよね。でも、例えばこれを ||を使って1つの式で5つ全ての関数を実行するようなケースで考えてみよう。こう。

!fn1() 
|| !fn2() 
|| fn3() 
|| !fn4() 
|| fn5() 

これでok。でもここでよく考えてみよう、関数をorで繋げる時は戻り値がfalsyじゃないといけないわけです。まあ当たり前やね。orは1個でもtruthyが出てきたらその時点で評価が終わるので、最後の式まで評価させるには全部falsyにしておかないといけないって感じです。

ところがどっこい、関数の戻り値がtruthyかfalsyかなんて関数を見なきゃ分かりません。まあこれも当然。今回の例だとfn1(), fn2(), fn4()は戻り値がtruthyなので!を付けてfalsyに変えていますが、これらの関数の戻り値がtruthyであることは関数を見なければ分かりません

そう、「戻り値が分からんから不便」...もうお気づきでしょうか。voidを使えば戻り値は必ずundefined、すなわちvoidを使えばあらゆる関数の戻り値はfalsyになるんです。いちいち関数の処理内容とか見なくてもいい。

void fn1()
|| void fn2()
|| void fn3()
|| void fn4()
|| void fn5()
|| void console.log(foo)
|| void fn10()
|| void fn42()
|| void console.log(bar)
|| void fn10000()

こんな感じ。評価する関数なんて一切見なくて良い、ひたすら || void を繰り返すだけ。これを例えばmain関数と組み合わせてこう。

const main = () =>
   void fn1()
|| void fn2()
|| void fn3()
|| void fn4()
|| void fn5()
|| void console.log(foo)
|| void fn10()
|| void fn42()
|| void console.log(bar)
|| void fn10000()

main()

あとこれが最も活用できると思うけど、JSXでDOMを返す時に他の処理を挟むことができます。こんな感じに。

const foo = bar =>
   void fn1()
|| void fn2()
|| void fn3()
|| void console.log(bar)
|| <div>{ bar }</div>

欠点

これまでの記事で 「void意外とやるやん!」って思ったあなた...残念ですがそれは幻想です

まずもって、1つの式で複数の関数を実行したい場面は極めて稀です。それこそ↑のJSXくらい。↑のmainとかは別にわざわざ1つの式にまとめる必要もないし。波括弧がなくなって綺麗&数学的に美しいってのはあるけどね。

そしてこれがわりと致命傷ですが、TypeScriptだとvoid || とかやると警告が出ます。実質使用不可です。TSそこまで詳しくないけどconsole.log()とかもorで繋げないので、void型には||とか&&使えないのかな?ごめんこの辺は不明。

更に言うと、上で散々しつこく書いた関数の戻り値がtruthyかfalsyかパッと見分からんって問題もTSだと型付いてるのでパッと見で分かります。

あれっ?voidの存在意義が...

さいごに

voidやっぱ引退しよう。極めて限定的な場面でしか使えねえや。僕よりずっと賢い方々が上手い使い方を考えてくれるのを楽しみに待ちましょう。以上。



PREV
2020-07-24
【JS】100vhはみ出る問題を解決するライブラリdiv-100vhについて

NEXT
2020-08-08
【JS】JavaScriptのifはどうしたら見やすくなるのか