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 StringをURLSearchParamsでパースして、
スプレッド構文を用いて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で書け?
友達と共有する程度なので。。。