「クエリ取得」で何をしたいのかをはっきりさせる
ここでの「クエリ取得」は、URL の ? 以降(クエリ文字列)から、パラメータを取り出して使いやすい形にすることです。
/search?q=JavaScript&page=2
この q や page の値を、JavaScript から安全に取り出したい。
画面遷移後に「さっきの検索条件」を復元したり、
URL で渡された token や id を使って処理したりするために、
「クエリをちゃんとパースしてオブジェクトにする」ユーティリティがあると、実務でかなり効きます。
まずは「クエリ文字列」の形を整理する
典型的な形
クエリ文字列は、基本的にこういう形をしています。
?q=JavaScript&page=2&sort=created_at
ルールを分解するとこうです。
?のあとに「クエリ部分」が続く&で「パラメータ同士」を区切る- 各パラメータは
key=valueの形 - key と value は URL エンコードされている(
%xx形式が混ざる)
なので、「クエリ取得ユーティリティ」がやるべきことは、ざっくり言うとこうです。
- 先頭の
?を外す &で分割してkey=valueのペアにするkeyとvalueをdecodeURIComponentで元に戻す- オブジェクトに詰める
これを毎回手書きするのは面倒なので、関数に閉じ込めます。
基本形:クエリ文字列 → オブジェクト
parseQueryString の実装
まずは、"?q=JavaScript&page=2" のような文字列を受け取って、{ q: "JavaScript", page: "2" } のようなオブジェクトにする関数です。
function parseQueryString(qs) {
const result = {};
if (!qs) return result;
const query = qs.startsWith("?") ? qs.slice(1) : qs;
if (query === "") return result;
const pairs = query.split("&");
for (const pair of pairs) {
if (!pair) continue;
const [rawKey, rawValue = ""] = pair.split("=", 2);
const key = decodeURIComponent(rawKey);
const value = decodeURIComponent(rawValue);
result[key] = value;
}
return result;
}
JavaScript重要ポイントをかみ砕いて説明する
ここはしっかり理解しておきたいところです。
1. ? を外してから処理する
const query = qs.startsWith("?") ? qs.slice(1) : qs;
JavaScriptlocation.search は "?q=..." のように ? 付きで返ってきます。
一方で、関数に直接 "q=..." を渡したいこともあります。
どちらでも動くように、「先頭が ? なら外す」という処理を入れています。
2. & で分割して「ペア」にする
const pairs = query.split("&");
JavaScriptここで ["q=JavaScript", "page=2"] のような配列になります。
空文字(&& が続いたときなど)はスキップしています。
3. key=value を 2 つに分けるときの注意
const [rawKey, rawValue = ""] = pair.split("=", 2);
JavaScriptsplit("=", 2) としているのは、value に = が含まれていても壊れないようにするためです。
例えば、"sort=created_at desc" は問題ないですが、"token=a=b=c" のような値も理論上ありえます。
split("=", 2) にしておけば、
rawKey→"token"rawValue→"a=b=c"
と、最初の = だけで分割してくれます。
4. key も value も decodeURIComponent する
const key = decodeURIComponent(rawKey);
const value = decodeURIComponent(rawValue);
JavaScriptエンコード側で encodeURIComponent を使っている前提なので、
デコード側も decodeURIComponent でペアにしてあげます。
スペースや日本語、&、= などが元の文字に戻ります。
実際の使用例でイメージを固める
location.search からクエリを取得する
ブラウザなら、こう書けます。
const params = parseQueryString(window.location.search);
// 例: URL が /search?q=JavaScript%20%E5%85%A5%E9%96%80&page=2 のとき
// params は { q: "JavaScript 入門", page: "2" }
JavaScriptあとは、フォームに値を戻したり、処理に使ったりできます。
searchInput.value = params.q ?? "";
currentPage = Number(params.page ?? 1);
JavaScript特定のキーだけを取り出す小さなユーティリティ
よく使うのは「特定の 1 つのパラメータだけ欲しい」パターンです。
function getQueryParam(qs, name) {
const params = parseQueryString(qs);
return params[name];
}
JavaScript使い方はこうです。
const q = getQueryParam(window.location.search, "q");
const token = getQueryParam(window.location.search, "token");
JavaScript「全部のパラメータはいらない、これだけ欲しい」というときに、parseQueryString の上にこういう薄いラッパーを乗せておくと、コードが読みやすくなります。
配列・複数値をどう扱うか(少し応用)
tag=js&tag=ts を配列として扱いたい場合
クエリ生成側で「同じキーを複数回出す」設計にしていると、
取得側でもそれを配列として扱いたくなります。
?tag=js&tag=ts&q=frontend
これを
{ tag: ["js", "ts"], q: "frontend" }
JavaScriptのようにしたい場合のバージョンです。
function parseQueryStringWithArray(qs) {
const result = {};
if (!qs) return result;
const query = qs.startsWith("?") ? qs.slice(1) : qs;
if (query === "") return result;
const pairs = query.split("&");
for (const pair of pairs) {
if (!pair) continue;
const [rawKey, rawValue = ""] = pair.split("=", 2);
const key = decodeURIComponent(rawKey);
const value = decodeURIComponent(rawValue);
if (key in result) {
const current = result[key];
if (Array.isArray(current)) {
current.push(value);
} else {
result[key] = [current, value];
}
} else {
result[key] = value;
}
}
return result;
}
JavaScript動きはこうなります。
parseQueryStringWithArray("?tag=js&tag=ts&q=frontend");
// { tag: ["js", "ts"], q: "frontend" }
JavaScript「同じキーが複数回出てきたら配列にする」というルールを決めておくと、
タグ検索や複数選択の条件を扱いやすくなります。
設計として意識してほしいこと
「クエリ生成」と「クエリ取得」をペアで考える
前に話した「クエリ生成」と今回の「クエリ取得」は、セットで設計すると強いです。
生成側:
toQueryString({ q: "JavaScript 入門", tag: ["js", "ts"] });
// "?q=JavaScript%20%E5%85%A5%E9%96%80&tag=js&tag=ts"
JavaScript取得側:
parseQueryStringWithArray("?q=JavaScript%20%E5%85%A5%E9%96%80&tag=js&tag=ts");
// { q: "JavaScript 入門", tag: ["js", "ts"] }
JavaScriptこのように、「どう出すか」と「どう読むか」をペアで決めておくと、
バックエンドとの連携や画面間の遷移がとても安定します。
「どこで decode するか」をはっきりさせる
なんとなく decodeURIComponent をあちこちで呼び始めると、
二重デコードやエラーの原因になります。
- 「URL からクエリを読むときだけ decode する」
- 「それ以外の文字列には decode をかけない」
という線引きを、ユーティリティのレイヤーで決めておくと、
アプリ全体の挙動が読みやすくなります。
ちょっとだけ手を動かしてみる
コンソールで、次の順番で試してみてください。
parseQueryString("?q=JavaScript%20%E5%85%A5%E9%96%80&page=2");
parseQueryString("tag=A%26B");
parseQueryStringWithArray("?tag=js&tag=ts&q=frontend");
getQueryParam("?q=hello&x=1", "q");
JavaScript「どのキーがどうデコードされて、どんなオブジェクトになるか」を、
自分の目で確認してみてください。
そのうえで、自分のプロジェクトに
export function parseQueryString(...) { ... }
export function parseQueryStringWithArray(...) { ... }
export function getQueryParam(...) { ... }
JavaScriptを置いて、
- クエリ全体が欲しい →
parseQueryString/parseQueryStringWithArray - 1 個だけ欲しい →
getQueryParam
という使い分けをルール化してみてください。
それだけで、あなたの「クエリ取得」は、
場当たり的な location.search.split("&") から、
意図と安全性を両立した“業務レベルの URL クエリユーティリティ”に一段レベルアップします。
