Last active
January 12, 2019 09:10
-
-
Save john-yuan/fac5c91a6f7b6b6dea4e73f00f5636e2 to your computer and use it in GitHub Desktop.
An util to encode object to query string or decode query string to object.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* An util to encode object to query string or decode query string to object. | |
* | |
* API: | |
* | |
* * `QS.encode(object: Object.<string, *>, keepArrayIndex?: boolean) => string` | |
* * `QS.decode(string: string) => Object.<string, *>` | |
* | |
* @author John Yuan <https://github.com/john-yuan> | |
* @see {@link https://gist.github.com/john-yuan/fac5c91a6f7b6b6dea4e73f00f5636e2} | |
*/ | |
var QS = (function () { | |
// namespace | |
var QS = {}; | |
// caches | |
var toString = Object.prototype.toString; | |
var hasOwn = Object.prototype.hasOwnProperty; | |
/** | |
* Encode the given object to URI Component encoded query string | |
* | |
* @param {Object.<string, *>} object The object to encode | |
* @param {boolean} [keepArrayIndex] Wether to keep array index | |
* @returns {string} Returns the URI Component encoded query string | |
*/ | |
QS.encode = function (object, keepArrayIndex) { | |
var key; | |
var keyValueArray = []; | |
keepArrayIndex = !!keepArrayIndex; | |
if ( isObject(object) ) { | |
for ( key in object ) { | |
if ( hasOwn.call(object, key) ) { | |
encodeKey(key, object[key], keyValueArray, keepArrayIndex); | |
} | |
} | |
} | |
return keyValueArray.join('&'); | |
}; | |
/** | |
* Decode the URI Component encoded query string to object | |
* | |
* @param {string} The URI Component encoded query string | |
* @returns {Object.<string, string>} Returns the decoded object | |
*/ | |
QS.decode = function (string) { | |
var object = {}; | |
var cache = {}; | |
var keyValueArray; | |
var index; | |
var length; | |
var keyValue; | |
var key; | |
var value; | |
// do not decode empty string or something that is not string | |
if (string && typeof string === 'string') { | |
keyValueArray = string.split('&'); | |
index = 0; | |
length = keyValueArray.length; | |
while (index < length) { | |
keyValue = keyValueArray[index].split('='); | |
key = decodeURIComponent(keyValue[0]); | |
value = keyValue[1]; | |
if (value) { | |
value = decodeURIComponent(value); | |
} else { | |
value = ''; | |
} | |
decodeKey(object, cache, key, value); | |
index += 1; | |
} | |
} | |
return object; | |
}; | |
/** | |
* Encode the speceifed key in the object | |
* | |
* @param {string} key The key name | |
* @param {any} data The data of the key | |
* @param {string[]} keyValueArray The array to store the key value string | |
* @param {boolean} keepArrayIndex Wether to keep array index | |
*/ | |
var encodeKey = function (key, data, keyValueArray, keepArrayIndex) { | |
var prop; | |
var index; | |
var length; | |
var value; | |
var subKey; | |
if ( isObject(data) ) { | |
for ( prop in data ) { | |
if ( hasOwn.call(data, prop) ) { | |
value = data[prop]; | |
subKey = key + '[' + prop + ']'; | |
encodeKey(subKey, value, keyValueArray, keepArrayIndex); | |
} | |
} | |
} else if ( isArray(data) ) { | |
index = 0; | |
length = data.length; | |
while (index < length) { | |
value = data[index]; | |
if ( keepArrayIndex || isArray(value) || isObject(value) ) { | |
subKey = key + '[' + index + ']'; | |
} else { | |
subKey = key + '[]'; | |
} | |
encodeKey(subKey, value, keyValueArray, keepArrayIndex); | |
index += 1; | |
} | |
} else { | |
// if data is null or undefined, treat it as empty string | |
if (data === null || data === undefined) { | |
data = ''; | |
// make sure that data is string if it is not object or array | |
} else if (typeof data !== 'string') { | |
data = '' + data; | |
} | |
key = encodeURIComponent(key); | |
data = encodeURIComponent(data); | |
value = key + '=' + data; | |
keyValueArray.push(value); | |
} | |
}; | |
/** | |
* Decode the specefied key | |
* | |
* @param {Object.<string, string>} object The object to hold the decoded data | |
* @param {Object.<string, *>} cache The object to hold cache data | |
* @param {string} key The key name to decode | |
* @param {any} value The value to decode | |
*/ | |
var decodeKey = function (object, cache, key, value) { | |
var rBracket = /\[([^\[]*?)?\]$/; | |
var rIndex = /(^0$)|(^[1-9]\d*$)/; | |
var indexOrKeyOrEmpty; | |
var parentKey; | |
var arrayOrObject; | |
var keyIsIndex; | |
var keyIsEmpty; | |
var valueIsInArray; | |
var dataArray; | |
var length; | |
// check wether key is something like `person[name]` or `colors[]` or | |
// `colors[1]` | |
if ( rBracket.test(key) ) { | |
indexOrKeyOrEmpty = RegExp.$1; | |
parentKey = key.replace(rBracket, ''); | |
arrayOrObject = cache[parentKey]; | |
keyIsIndex = rIndex.test(indexOrKeyOrEmpty); | |
keyIsEmpty = indexOrKeyOrEmpty === ''; | |
valueIsInArray = keyIsIndex || keyIsEmpty; | |
if (arrayOrObject) { | |
// convert the array to object | |
if ( (! valueIsInArray) && isArray(arrayOrObject) ) { | |
dataArray = arrayOrObject; | |
length = dataArray.length; | |
arrayOrObject = {}; | |
while (length--) { | |
if (arrayOrObject[length] !== undefined) { | |
arrayOrObject[length] = dataArray[length]; | |
} | |
} | |
} | |
} else { | |
arrayOrObject = valueIsInArray ? [] : {}; | |
} | |
if ( keyIsEmpty && isArray(arrayOrObject) ) { | |
arrayOrObject.push(value); | |
} else { | |
// arrayOrObject is array or object here | |
arrayOrObject[indexOrKeyOrEmpty] = value; | |
} | |
cache[parentKey] = arrayOrObject; | |
decodeKey(object, cache, parentKey, arrayOrObject); | |
} else { | |
object[key] = value; | |
} | |
}; | |
/** | |
* Check wether the variable is an object | |
* | |
* @param {any} it The variable to check | |
* @returns {boolean} Returns `true` if it is an object | |
*/ | |
var isObject = function (it) { | |
return '[object Object]' === toString.call(it); | |
}; | |
/** | |
* Check wether the variable is an array | |
* | |
* @param {any} it The variable to check | |
* @returns {boolean} Returns `true` if it is an array | |
*/ | |
var isArray = function (it) { | |
return '[object Array]' === toString.call(it); | |
}; | |
// expose the API | |
return QS; | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment