---
type: how-to
language: javascript
slug: url/query
title: "URL のクエリ文字列を読む・組み立てる"
title_tag: "JavaScript URLSearchParams — クエリの取得と組み立て"
summary: >
  自分で split() しないでください。URLSearchParams が符号化も復号も同じ値の複数指定も扱います。
  必ず文字列で返ること、空とキー無しの見分け、+ と %20 の違いまで実行して確かめます。
description: >
  URLSearchParams は符号化・復号・同じキーの複数指定をまとめて扱います。値が必ず文字列で返ること、
  無いキーが null になること、スペースが + になる理由まで実行して確かめられます。
status: published
difficulty: 2
minutes: 8

versions:
  verified: "Node 22.22.3"
  since: "ES2015"
  deprecated: null
  removed: null

sources:
  - title: "URLSearchParams — URL Standard (WHATWG)"
    url: "https://url.spec.whatwg.org/#interface-urlsearchparams"
  - title: "URL — URL Standard (WHATWG)"
    url: "https://url.spec.whatwg.org/#url-class"
  - title: "URLSearchParams — MDN"
    url: "https://developer.mozilla.org/ja/docs/Web/API/URLSearchParams"

terms: [クエリ文字列, 百分率符号化, 標準組み込み]

links:
  related:
    - javascript/reference/string/split
    - javascript/how-to/string/to-number
    - javascript/reference/json/parse

content_updated_at: 2026-09-08
published_at: 2026-09-08
---

## 答え

**`split()` で自分で分解しないでください。**

```js run
const params = new URLSearchParams('?q=猫&page=2');

console.log(params.get('q'));
console.log(params.get('page'));
```
```output
猫
2
```

先頭の `?` は付いていても付いていなくても構いません。
[key:復号は自動]です。`%E7%8C%AB` のままにはなりません。

[dim:これは言語ではなくブラウザ側の仕様（URL Standard）ですが、Node にも同じものが入っています。どちらでも同じように使えます。]

## 値は必ず文字列で返る

```js bad
const params = new URLSearchParams('page=2');
const page = params.get('page');

console.log(typeof page);
console.log(page + 1);
```
```output
string
21
```

**足し算のつもりが繋がりました。**
数として使うなら、その場で変換してください。

```js run
const params = new URLSearchParams('page=2');
const page = Number(params.get('page'));

console.log(page + 1);
```
```output
3
```

→ [文字列を数値に変換する](/ja/javascript/how-to/string/to-number/)

## 無いキーは `null`

```js run
const params = new URLSearchParams('a=&b=1');

console.log(JSON.stringify(params.get('a')));
console.log(JSON.stringify(params.get('none')));
console.log(params.has('a'), params.has('none'));
```
```output
""
null
true false
```

**「空で指定されている」と「そもそも無い」は別です。**
`get()` だけでは見分けられないので、`has()` を使ってください。

既定値を入れるときも、この差が効きます。

```js bad
const params = new URLSearchParams('keyword=');

console.log(JSON.stringify(params.get('keyword') || 'すべて'));
console.log(JSON.stringify(params.get('keyword') ?? 'すべて'));
```
```output
"すべて"
""
```

`||` は空文字も既定値に倒します。どちらが正しいかは仕様しだいです。
→ [?. と ??](/ja/javascript/reference/operator/optional-chaining/)

## 同じキーが複数あるとき

```js run
const params = new URLSearchParams('tag=a&tag=b');

console.log(params.get('tag'));
console.log(params.getAll('tag'));
```
```output
a
[ 'a', 'b' ]
```

`get()` は[bad:最初の1つしか返しません。]
チェックボックスのように複数付きうるものは、**必ず `getAll()`** です。

## 組み立てる

```js run
const params = new URLSearchParams({ q: '猫 犬', page: '2' });

console.log(params.toString());
```
```output
q=%E7%8C%AB+%E7%8A%AC&page=2
```

**符号化も自動です。** `encodeURIComponent()` を自分で呼ぶ必要はありません。

| したいこと | 使うもの |
|---|---|
| 足す（同じキーを増やす） | `append()` |
| 置き換える（同じキーは1つに） | `set()` |
| 消す | `delete()` |

```js run
const params = new URLSearchParams({ page: '2' });

params.append('tag', 'a');
params.append('tag', 'b');
console.log(params.toString());

params.set('tag', 'c');
console.log(params.toString());

params.delete('page');
console.log(params.toString());
```
```output
page=2&tag=a&tag=b
page=2&tag=c
tag=c
```

[bad:`set()` は同じキーを全部まとめて1つにします。] 増やしたいなら `append()` です。

## URL ごと組み立てる

```js run
const url = new URL('https://codetaizen.com/ja/search/?q=1');

url.searchParams.set('q', '猫');
url.searchParams.set('page', '2');

console.log(url.toString());
console.log(url.pathname, url.origin);
```
```output
https://codetaizen.com/ja/search/?q=%E7%8C%AB&page=2
/ja/search/ https://codetaizen.com
```

`url.searchParams` を触ると、**`url` 自身も書き換わります。**
文字列を繋いで組み立てるより、こちらのほうが安全です。

## スペースが `+` になる

```js run
console.log(new URLSearchParams({ a: 'x y' }).toString());
console.log(encodeURIComponent('x y'));
```
```output
a=x+y
x%20y
```

**同じスペースでも書き方が2つあります。**
クエリ文字列では `+` が歴史的に使われ、`URLSearchParams` はそちらを選びます。

読むときはどちらも正しく戻ります。

```js run
console.log(new URLSearchParams('a=x+y').get('a'));
console.log(new URLSearchParams('a=x%20y').get('a'));
```
```output
x y
x y
```

[bad:自分で `encodeURIComponent()` した文字列を、さらに `set()` に渡さないでください。]
二重に符号化され、`%2520` のような形になります。

## よくある間違い：`split()` で自分で分ける

```js bad
const query = 'q=%E7%8C%AB&tag=a&tag=b';

const parsed = Object.fromEntries(query.split('&').map((part) => part.split('=')));

console.log(parsed);
```
```output
{ q: '%E7%8C%AB', tag: 'b' }
```

**2つ壊れています。**

- 復号されないので `%E7%8C%AB` のまま
- 同じキーが[bad:後ろで上書きされて 1つ消えた]

値の中に `=` が入っていれば、そこでも切れます。
**自分で書かないでください。**

## まとめ

- クエリは `URLSearchParams` に任せる。**`split()` で分けない**
- 返るのは**必ず文字列**。数として使うなら変換する
- 無いキーは `null`、空指定は空文字。**見分けるなら `has()`**
- 同じキーが複数あるなら `getAll()`
- 足すのは `append()`、置き換えるのは `set()`
- 符号化は自動。[bad:自分で符号化してから渡さない]
- URL ごと扱うなら `new URL()` の `searchParams`
