クエリーをオブジェクトに

URLの「?」以降のクエリー文字列をオブジェクトに変換します。また、その逆も行います。 2018-06-29

 URLの「?」以降のクエリー文字列は、CGIの引数でよく用いられます。しかし、CGIはサーバー側の処理が必要で、HTMLファイルのみで完結しません。

 サーバー側のプログラムを書かずに、HTMLだけで処理を完結させたいことは、時々あります。そうした時に、クエリー文字列をJavaScriptのオブジェクト化して取り出したり、その逆を行ったりできると便利です。この関数では、そうした処理を手軽に行います。

 たとえばゲームの棋譜的な手順をクエリー文字列として保存しておき、そのデータを用いて途中から再開するなどして、利用できます。

 ファイル構成は以下の通りです。>>ダウンロード

※ 初期化用関数「init」の処理については「Webブラウザ/Node.js 互換関数」をご覧下さい。Node.js用の処理は、今回のコードにはありません。

サンプル動作

sample/queryToObj.js

'use strict';

(function() {
	const _t = init('com.crocro.util');

	// queryToObj | クエリーをオブジェクトに
	_t.queryToObj = function() {
		// 変数の初期化
		const obj = {};

		// クエリー文字列があるなら生成
		if (location.search.length > 1) {
			const qArr = location.search.substr(1).split('&');
			qArr.forEach(x => {
				// 分割
				const kvArr = x.split('=');
				if (kvArr.length < 2) {return}

				// オブジェクトに格納
				const key = kvArr[0];
				const val = decodeURIComponent(kvArr[1]);
				obj[key] = val;
			});
		}
		return obj;
	};

	// objToQuery | オブジェクトをクエリーに
	_t.objToQuery = function(obj) {
		// 変数の初期化
		const res = Object.keys(obj).map(x => {
			return x + '=' + encodeURIComponent(obj[x]);
		}).join('&');

		return res;
	};

	// 初期化用関数
	function init(p) {
		return ((o, p) => {
			p.split('.').forEach(k => o = o[k]||(o[k]={}));
			return o})(window, p);
	};
})();

解説

 まずは、「queryToObj」です。

 「location.search」で、「?」以降のクエリー文字列を取り出せます。この文字列は先頭に「?」を含んでいるので、「substr(1)」で0文字目を除いた1文字目以降を取得して、「&」で分割して配列にしています。

 この配列の各要素を「=」で分割したあと、値の部分を「decodeURIComponent」でデコードしています。そして、「key」「val」の値を元に、オブジェクトを構築して戻り値にしています。


 次に、「objToQuery」です。

 「Object.keys(obj)」で、オブジェクトのキーの配列を得て、その配列をもとに「map」内でキーと値を「=」で繋いだ文字列を作成していきます。その際に、値は「encodeURIComponent」でエンコードします。

  最後に、「join('&')」として「&」で配列を結合して、求める文字列を得ます。


 サンプルでは、「location.href」にURLを代入して、ページを遷移しています。ページを遷移せずにURLのみを書き換える場合は、HTML5で加えられた「history.pushState()」や「history.replaceState()」を用います(参考:ブラウザの履歴を操作する)。

 「history.pushState('', '', url)」や「history.replaceState('', '', url)」として、第3引数に絶対URLや相対URLを入れることで、アドレスバーのURLを書き換えます。この時、「pushState」はページ遷移の履歴を残し、「replaceState」は履歴を残しません。

 URL文字列を絶対パスで書く場合は、same origin(プロトコルとポートとホストが等しい)である必要があります。

queryToObj|クエリーをオブジェクトに

URLの「?」以降のクエリー文字列を、デコードしてオブジェクトに変換します。

@return URLの「?」以降のクエリー文字列のオブジェクト。

サンプル

const queryToObj = com.crocro.util.queryToObj;
const obj = queryToObj();
console.log(JSON.stringify(obj, null, '  '));
// {
//   "name_1530214040495": "あいうえお",
//   "url_1530214040495": "https://crocro.com/"
// }

objToQuery | オブジェクトをクエリーに

オブジェクトをエンコードして、URLの「?」以降のクエリー文字列に変換します。

@param {Object} obj - オブジェクト。
プロパティの階層が1つのオブジェクトを指定します。

@return URLの「?」以降のクエリー文字列。

サンプル

const objToQuery = com.crocro.util.objToQuery;
const obj = {};
obj['name_' + +new Date()] = 'あいうえお';
obj['url_'  + +new Date()] = 'https://crocro.com/';
console.log(objToQuery(obj));
// name_1530214040495=%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A&url_1530214040495=https%3A%2F%2Fcrocro.com%2F

sample/index.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title>クエリーをオブジェクトに - JavaScript実用サンプルコード解説付き</title>

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js">
    </script>

    <script src="queryToObj.js"></script>
    <script src="main.js"></script>
    <link rel="stylesheet" href="main.css">
  </head>
  <body>
    <textarea id="src" style="height: 20em;"></textarea>
    <button id="exec">実行</button>
    <button id="reset">リセット</button>
    <textarea id="dst" style="height: 8em;"></textarea>
  </body>
</html>

sample/main.js

'use strict';

$(function() {
	// 変数の初期化
	const $src   = $('#src');
	const $dst   = $('#dst');
	const $exec  = $('#exec');
	const $reset = $('#reset');

	// 値のセット
	$src.val(String.raw`
/*
↓URL
${location.href}
*/

const queryToObj = com.crocro.util.queryToObj;
const objToQuery = com.crocro.util.objToQuery;

// クエリーをオブジェクトにして取得
const obj = queryToObj();

// 値を追加
obj['name_' + +new Date()] = 'あいう';
obj['url_'  + +new Date()] = 'https://crocro.com/';

// ページを遷移
location.href = '?' + objToQuery(obj);
	`.trim());

	// コンソール ログのラップ
	const log = console.log;
	console.log = function() {
		for (let i = 0; i < arguments.length; i ++) {
			$dst.append(arguments[i] + ' ');
		}
		$dst.append('\n');
		log.apply(console, arguments);
	};

	// クエリー文字列を出力
	const queryToObj = com.crocro.util.queryToObj;
	const obj = queryToObj();
	console.log(JSON.stringify(obj, null, '  '));

	// クリック時の処理
	$exec.click(() => {
		$dst.empty();
		eval($src.val());
	});

	$reset.click(() => {
		location.href = '.';
	});
});

sample/main.css

html,
body {
	margin: 0;
	padding: 0;
}

textarea,
button {
	box-sizing: border-box;
	width: 100%;
	vertical-align:bottom;
}
textarea {
	height: 5em;
}

紹介

Steamでゲームをリリースした時の経験をマニュアル的にまとめた本です。
8bit風RTS「TinyWar」のアルゴリズムを、コード付きで解説した本です。
JavaScriptから手軽に扱える形態素解析器『kuromoji.js』を使い、日本語を分解して遊ぶ本です。
node.jsを使い、「Google Chrome」のユーザーデータを、自動処理でメンテナンスするプログラムを開発する本です。
HTML5でローカルアプリが作れるNW.jsで、同人ゲームを作るための基礎知識の本です。
シミュレーションRPG「TinySRPG」のアルゴリズムを、コード付きで解説した本です。
JavaScriptの実行時エラーを分類して、ワンライナーのソースコードとエラーメッセージを収録した本です。
禁止文字つきコードゴルフを1年以上出題して、その解答ノウハウをまとめた本です。
2011年の春ごろに、Javaで「NyARToolKit」互換のARマーカー認識プログラムを書いた時のレポートです。