【JavaScript】URLSearchParamsを使っていい感じにURLパラメータを作る

# 概要


以前投稿した[【JavaScript】URLパラメータを今風に取得する](https://qiita.com/g-iki/items/8c6dbc8f55051fce834c) で使用した[URLSearchParams](https://developer.mozilla.org/ja/docs/Web/API/URLSearchParams)を使用すると、いい感じにURLパラメータを作ることができたのでそのメモです。

# あんまりおしゃれでない実装(個人的主観)

```js
location.href = '/search?'
    + (q ?? 'q=' + q)
    + (start ?? 'start=' + start)
    + ...
```

(パラメータはGoogle検索のキーワードとページ)
パラメータ指定があったらひたすら文字列結合をしていく方法。
パラメータが少ないうちはいいですが、なんか野暮ったい感じ。。。

# いいかんじの実装(個人的主観)

- URLパラメータをすべて作る
- もともとのURLパラメータの内、一部分だけを書き換える

の2パターンの例を紹介します。

## URLパラメータをすべて作る


```js

const makeURLParameter = (obj) => {
    return new URLSearchParams(
        Object.fromEntries(
            Object.entries(obj).filter(
                ([_k, v]) => v !== undefined
            )
        )
    ).toString();
}
```

- [Object.entries()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/entries)で連想配列を配列化
- その配列に対し、[filter](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/filter)を使用し、値が設定されていないものを排除(`filter(([_k, v]) => v !== undefined)`)
- [Object.fromEntries()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/fromEntries)で再度連想配列化
- [URLSearchParams.toString()](https://developer.mozilla.org/ja/docs/Web/API/URLSearchParams/toString)で`?`が付いていないURLパラメータ文字列を生成します。


例えばこれで(同じドメイン内なら)
```js
location.href = location.pathname
    + '?'
    + makeURLParameter(
        {
            q:'google',
            start: 20
        }
    );
```

のような呼び出しをすることで、パラメータ部分をすべて書き換えたURLに移動します。


## もともとのURLパラメータの内、一部分だけを書き換える

もともとのURLパラメータが例えば`?q=google&start=30&num=15`という状態で、
`q=youtube&start=30`のようにもともと指定されているパラメータを残しつつ書き換えたい時の書き方です。


```js
const remakeURLParameter = (obj) => {
    const oldParam = Object.fromEntries(new URLSearchParams(window.location.search));
    const newParam = { ...oldParam, ...obj };
    
    return new URLSearchParams(
        Object.fromEntries(
            Object.entries(newParam).filter(
                ([_k, v]) => v !== undefined
            )
        )
    ).toString();
}
```

本質的には上のものと同じですが、もとのURLを取得するために
- `new URLSearchParams(window.location.search)`でもともとのURLパラメータを取得
- それを[Object.entries()](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Object/entries)で連想配列化
- 引数で指定された連想配列を[スプレッド構文](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax)で結合

として、それ以降は上のものと同じです。

呼び出し的には

```js
location.href = location.pathname
    + '?'
    + remakeURLParameter(
        {
            q:'youtube',
            num: undefined
        }
    );
```

のように呼び出します。

---


## もともとのURLパラメータの内、一部分だけを書き換える②

[コメント欄](https://qiita.com/g-iki/items/f18395b173266b85d26a#comment-a83e795fda9369e6d1e0) で @f03858 さんにご紹介頂いた実装を転載します。

```js
const URLSearchParamsReplace = (params, baseURL = location.href) => {
  const url = new URL(baseURL);
  Object.entries(params).forEach(([key, value]) =>
    value === undefined ? url.searchParams.delete(key) : url.searchParams.set(key, value));

  return url.href;
};

console.log(URLSearchParamsReplace(
  // new search params
  {
    q: 'youtube',
    num: undefined,
  },

  // base url (省略可)
  'https://example.com/?q=google&start=30&num=15',
));
// https://example.com/?q=youtube&start=30
```

URLSearchParamsで用意されている[URLSearchParams.delete](https://developer.mozilla.org/ja/docs/Web/API/URLSearchParams/delete)や[URLSearchParams.set](https://developer.mozilla.org/ja/docs/Web/API/URLSearchParams/set)を使用した実装ですね！

こちらの方がコードをぱっと見で見たときにパラメータにセットしてる、消してるがわかりやすいですね！
ありがとうございました！