JavaScript:递归编码和解码查询字符串(将对象转换为查询字符串,将查询字符串转换为对象)。

3

我想将一个复杂的json / javascript对象编码为标准查询字符串格式。 我希望能够将这个查询字符串解码回json / javascript对象。 必须递归地处理数组,对象,字符串,布尔和数字。

我以为这很容易,但被证明是错误的。有没有人有想法如何解决这个问题? 可以用Javascript或最好用Typescript。

2个回答

2

我认为,你想要做的是对嵌套对象进行编码和解码。

虽然没有单一的标准,但通常会使用查询字符串(QS)语法:

{
    "attribute": "value",
    "array": ["apples", "bananas"],
    "object": { "number": 55 },
}

will become:

?attribute=value&array[0]=apples&array[1]=bananas&object[number]=55

示例代码:

function decode(querystring: string): object {
    function parseValue(value: string): any {
        if (value === 'TRUE') return true;
        if (value === 'FALSE') return false;
        return isNaN(Number(value)) ? value : Number(value);
    }

    function dec(list: any[], isArray = false): object {
        let obj: any = isArray ? [] : {};

        let recs: any[] = list.filter((item) => {
            if (item.keys.length > 1) return true;
            obj[item.keys[0]] = parseValue(item.value);
        });

        let attrs = {};
        recs.map((item) => {
            item.key = item.keys.shift();
            attrs[item.key] = [];
            return item;
        }).forEach((item) => attrs[item.key].push(item));

        Object.keys(attrs).forEach((attr) => {
            let nextKey = attrs[attr][0].keys[0];
            obj[attr] = dec(attrs[attr], typeof nextKey === 'number');
        });

        return obj;
    }

    return dec(
        querystring
            .split('&')
            .map((item) => item.split('=').map((x) => decodeURIComponent(x)))
            .map((item) => {
                return {
                    keys: item[0]
                        .split(/[\[\]]/g)
                        .filter((n) => n)
                        .map((key) => (isNaN(Number(key)) ? key : Number(key))),
                    value: item[1],
                };
            })
    );
}

export function encode(object: object): string {
    function reducer(obj, parentPrefix = null) {
        return function (prev, key) {
            const val = obj[key];
            key = encodeURIComponent(key);
            const prefix = parentPrefix ? `${parentPrefix}[${key}]` : key;

            if (val == null || typeof val === 'function') {
                prev.push(`${prefix}=`);
                return prev;
            }

            if (typeof val === 'boolean') {
                prev.push(`${prefix}=${val.toString().toUpperCase()}`);
                return prev;
            }

            if (['number', 'string'].includes(typeof val)) {
                prev.push(`${prefix}=${encodeURIComponent(val)}`);
                return prev;
            }

            prev.push(
                Object.keys(val).reduce(reducer(val, prefix), []).join('&')
            );
            return prev;
        };
    }

    return Object.keys(object).reduce(reducer(object), []).join('&');
}

根据字符串表示来猜测数据类型是一个不好的想法。许多值无法完整地进行往返转换。此外,Stack Overflow上的答案应该是自包含的;外部链接可能会失效。 - Ry-
我明白了。在字符串中添加引号是个好主意吗?像这样:?number=1234&string="1234"&boolean=true - kopilot.schneider

-1
const obj = { key: 1, key1: 2, key2: 3 }
const params = encodeURIComponent(JSON.stringify(obj))
window.location.href = `http://example.com/?query=${params}`

像这样结束:

http://example.com/?query=%7B%22key%22%3A1%2C%22key1%22%3A2%2C%22key2%22%3A3%7D


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接