Help us understand the problem. What is going on with this article?

JavaScriptでURLパラメーターをライブラリ無しでワンライナーで処理してみる。

More than 1 year has passed since last update.

JavaScriptの機能が貧弱と言われたのは今は昔、ES6以降の進化が著しいのは皆さんの知るとおりです。今ではライブラリに頼らずとも、複雑な処理をコンパクトに実装することができるようになりました。

今やRubyに優るとも劣らぬほどワンライナーで実装できるようになり、今回はライブラリを使わずにJavaScriptの標準機能だけでURLパラメーターのパースと復元をワンライナーで書いてみました。

URLパラメーターを1行でオブジェクト型にする

さてこのようなURLパラメーターを用意しました。

const queryString = '?name=ichiro&team=mariners&birthplace=aichi';

オブジェクトにするとこのようになりますね。

{
  name: 'ichiro',
  team: 'mariners',
  birthplace: 'aichi'
}

文字列をオブジェクト型にするには皆さんどうしていますか?
外部ライブラリとしてquery-stringが使われることもありますが、今ではライブラリに頼らなくても簡単に実装できます。

それでは一行で実装してみましょう。

[...new URLSearchParams(queryString).entries()].reduce((obj, e) => ({...obj, [e[0]]: e[1]}), {});

このような感じになります。
実行すると、しっかり上記のオブジェクトに変換されますが、どんなことを行っているのでしょうか。

パラメーターのパースを解説

ちなみに先ほどのワンライナーは無理やり一行にした感があり、適切に整形すると次のようになります。

[...new URLSearchParams(queryString).entries()]
  .reduce((obj, e) => ({...obj, [e[0]]: e[1]}), {});

まず知っておくべきなのはURLSearchParamsというインターフェースです。これを使うことで、驚くほど柔軟にURLパラメーターを操作できるようになります。

先頭の「?」の有無は問題にならず、キーごとに追加・削除・編集できるほか、entries()メソッドを呼ぶと全てのキー・バリューを含むイテレータを返してくれます。

[...new URLSearchParams(queryString).entries()]によってイテレータの実行結果を配列として受け取り、[[key, value]]という形式の二次元配列が取得されます。

これをreduceを使って、初期化されたオブジェクトを上書きしながら返すことで、キーがどれだけ増えても一つのオブジェクトを生成することができます。

JavaScriptはとても便利になった反面、表現が多彩になったことで初心者の方には敷居が高くなった感は否めませんが、慣れればこのような記法もさほど苦せず書けるようになるでしょう。

パフォーマンスを重視したり、IE対応をする場合

URLSearchParamsはモダンブラウザには軒並み搭載されていますが、残念ながらIEは対応していません。またBabelで後方互換をもたせる場合も、別途polyfillファイルを入れなければなりません。

そして何よりURLSearchParamsのインスタンスを生成するのにもコストがかかるので、パフォーマンスを重視するなら使わない方が良いでしょう。

こうしたケースに対応するには次のように実装します。

queryString.substring(1).split('&').map((p) => p.split('=')).reduce((obj, e) => ({...obj, [e[0]]: e[1]}), {});

さすがにワンライナーに盛りすぎですが、整形しても二行なので十分コンパクトにまとまっています。

queryString.substring(1).split('&').map((p) => p.split('='))
  .reduce((obj, e) => ({...obj, [e[0]]: e[1]}), {});

オブジェクトをStringに戻す

それでは逆にオブジェクトをString型に戻すにはどのようにすれば良いでしょうか。こちらはもっとシンプルで次のようになります。

'?' + Object.entries(params).map((e) => `${e[0]}=${e[1]}`).join('=');

オブジェクトをObject.entriesに渡すと[[key, value]]の二次元配列となり、それを「key=value」の形式で配列にまとめ、最後に「=」で結合すればURLパラメーターの出来上がりです。とても楽ですね!

ES5時代はjQueryのメソッドを使ったりしなければ冗長になっていましたが、今ではこんなに柔軟かつコンパクトに実装することができます。

JavaScriptは進化が早い余り、個別のユースケースに対してサンプルを調べても古い記法が出ることが多く、試しに調べてみたところ、forEachで回しながらオブジェクトを生成する記法が見られました。

JSはキャッチアップが大変と言われていますが、これまで表現できなかった手段がどんどん掘り起こされるのはエンジニアとして楽しみな瞬間でもあるので、ぜひ皆さんも自分なりの柔軟な記法を発掘してみてください。

ttiger55
GoやTypeScriptを書きます。最近はデータ構造やアルゴリズムを勉強しています。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away