見出し画像

Javascript で Query String をパーシング 処理のメモ

■ 概要

Qiitaの記事で見つけた、Query Stringをパースするコード。スプレッド構文、ラムダ式、リターン省略と、最近のパラダイムの構文でレベル高めだったので、ゆっくりと読み解いてみる。

・JavaScriptでURLパラメーターをライブラリ無しでワンライナーで処理してみる。 - Qiita
https://qiita.com/ttiger55/items/22e0f676ff6101336eaf

■ 対象の処理コード

[...new URLSearchParams(window.location.search).entries()].reduce(function(obj, e) {return {...obj, [e[0]]: e[1]}}, {});

※不用意にラムダ式を使いたくないため、function文に書き換え。

■ 結論

Query StringURLSearchParamsでパースして、
 スプレッド構文を用いてKey + Valueのセットの2次元配列に展開
 => String[n][2];
・reduceで2次元目を回して各配列(Array)連想配列(Hash)
 ※初期値は0要素の連想配列(Hash)

■ 解析(1) Query Stringの抽出

URL: http://example.org/aaa/bbb?ccc=111&ddd&eee=333

window.location.search
"?ccc=111&ddd&eee=333"

■ 解析(2) QueryStringのパース

new URLSearchParams('?ccc=111&ddd&eee=333')
URLSearchParams {}

痛レーター

new URLSearchParams("?ccc=111&ddd&eee=333").entries()
Iterator {}

なかみが分からないのでスプレッド構文で分解

[...new URLSearchParams('?ccc=111&ddd&eee=333').entries()]
[...new URLSearchParams('?ccc=111&ddd&eee=333')]
(3) [Array(2), Array(2), Array(2)]
    0: (2) ["ccc", "111"]
    1: (2) ["ddd", ""]
    2: (2) ["eee", "333"]
    length: 3
    __proto__: Array(0)

ただ二次元配列でした。(´・ω・`)
あとentries()で取れるイテレータがなくても同じ結果になった。

■ 解析(3-1) Array.reduce()

[["ccc", "111"], ["ddd", ""], ["eee", "333"]].reduce(function(obj, e) {return {...obj, [e[0]]: e[1]}}, {});
{ccc: "111", ddd: "", eee: "333"}

🤔

■ 解析(3-2) Array.reduce()をより分解

・(参考) Array.prototype.reduce() - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

let array = [["ccc", "111"], ["ddd", ""], ["eee", "333"]];
let callback = function(obj, e) {
    let ret = {...obj, [e[0]]: e[1]};
    console.info('------------------------------------------------------');
    console.info('obj= ', obj);
    console.info('e = ', e);
    console.info('ret = ', ret);
    return ret;
};
let initialValue = {};
array.reduce(callback, initialValue);
------------------------------------------------------
obj= {}                                                   # 連想配列(Hash)
e = (2) ["ccc", "111"]                              # 配列(Array)
ret = {ccc: "111"}                                    # 連想配列(Hash)
------------------------------------------------------
obj= {ccc: "111"}                                     # 連想配列(Hash)
e = (2) ["ddd", ""]                                    # 配列(Array)
ret = {ccc: "111", ddd: ""}                        # 連想配列(Hash)
------------------------------------------------------
obj= {ccc: "111", ddd: ""}                        # 連想配列(Hash)
e = (2) ["eee", "333"]                               # 配列(Array)
ret = {ccc: "111", ddd: "", eee: "333"}      # 連想配列(Hash)

{ccc: "111", ddd: "", eee: "333"}               # reduceの結果

■ おまけ① 戦うラムダ式

・[] - 配列を返す

(function() {return ['aaa', 'bbb'];})();   // function
(() => {return ['aaa', 'bbb'];})();        // ラムダ式
(() => (['aaa', 'bbb']))();                // ラムダ式 + return省略
(2) ["aaa", "bbb"]

・{} - 連想配列を返す

let key = "KEY";
let val = "VAL";

// function
(function() {return {KEY: 'VAL'};})();
(function() {return {[key]: val};})();    // 変数展開

// ラムダ式
(() => {return {KEY: 'VAL'};})();
(() => {return {[key]: val};})();         // 変数展開

// ラムダ式 + return省略
(() => ({KEY: 'VAL'}))();
(() => ({[key]: val}))();                 // 変数展開
{KEY: "VAL"}

・超進化!

[略].reduce(function(obj, e) {return {...obj, [e[0]]: e[1]}}, {});
[略].reduce((obj, e) => {return {...obj, [e[0]]: e[1]}}, {});
[略].reduce((obj, e) => ({...obj, [e[0]]: e[1]}), {});

■ おまけ② スプレッド構文イジメ

・(1-1) 配列にシンプルにスプレッド

['ccc', ...['aaa', 'bbb']]
[...['aaa', 'bbb'], 'ccc']
(3) ["ccc", "aaa", "bbb"]
(3) ["aaa", "bbb", "ccc"]

😃 普通。

・(1-2) 配列に2次元配列をスプレッド

[...[['aaa', 'bbb'], ['ccc', 'ddd']], 'eee']
(3) [Array(2), Array(2), "eee"]
    0: (2) ["aaa", "bbb"]
    1: (2) ["ccc", "ddd"]
    2: "eee"
    length: 3
    __proto__: Array(0)

🤔 ジャグった。。。まぁ違和感はない。

・(1-3) 配列に連想配列をスプレッド

[...{hoge:'gebu', foo:'bar'}, 'eee']
Uncaught TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
at <anonymous>:1:1

😇 ご臨終です。当然ですよねー・・・

・(2-1) 連想配列にシンプルにスプレッド

{...{hoge:'gebu', foo:'bar'}, piyp:'fuga'}
{piyp:'fuga', ...{hoge:'gebu', foo:'bar'}}
{hoge: "gebu", foo: "bar", piyp: "fuga"}
{piyp: "fuga", hoge: "gebu", foo: "bar"}

😃 納得の連想配列。

・(2-2) 連想配列に配列をスプレッド

{...['aaa', 'bbb'], piyp: 'fuga'}
{0: "aaa", 1: "bbb", piyp: "fuga"}

🤔 自動でindexがkeyの連想配列として扱われて結合された。なるほど。。。

・(2-3) 連想配列に配列をスプレッド (キーの重複)

{...['aaa', 'bbb'], 0: 'fuga'}
{0: 'fuga', ...['aaa', 'bbb']}
{0: "fuga", 1: "bbb"}
{0: "aaa", 1: "bbb"}

👹 後勝ちじゃ!

・(3-1) 連想配列x配列を配列としてブレンド

[...['aaa', 'bbb'], {0: 'fuga'}]
(3) ["aaa", "bbb", {…}]
    0: "aaa"
    1: "bbb"
    2: {0: "fuga"}
    length: 3
    __proto__: Array(0)
[{0: 'fuga'}, ...['aaa', 'bbb']]
(3) [{…}, "aaa", "bbb"]
    0: {0: "fuga"}
    1: "aaa"
    2: "bbb"
    length: 3
    __proto__: Array(0)

🤔 連想配列オブジェクトがぶっこまれた。

・(3-2) 連想配列x配列を連想配列としてブレンド

{...['aaa', 'bbb'], {0: 'fuga'}}
Uncaught SyntaxError: Rest parameter must be last formal parameter

😇 構文エラー扱いでダメです。


{{0: 'fuga'}, ...['aaa', 'bbb']}
Uncaught SyntaxError: Unexpected token ':'

😇 構文エラー扱いでダメです。

■ おまけ③

・スプレッド構文 - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Operators/Spread_syntax

・反復処理プロトコル - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Iteration_protocols

・Array.prototype.reduce() - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce

■ 余談

Qiitaで書け?
友達と共有する程度なので。。。

いいなと思ったら応援しよう!