Создание и парсинг строки запроса


В момент скуки, я решил написать два метода, один из которых будет создавать строку запроса, а другой будет разобрать его, ограничения я наложил на себя в том, что каждый способ не более одного заявления. Результатом является не то, что я бы рассмотреть возможность использования на работе или в моих личных проектов, потому что это моя причина для разноски этот вопрос заключается в том, что я хотел бы знать, как, учитывая ограничения я поставил для себя, кодекса можно было бы улучшить? Похоже, что лучший код можно написать, чтобы решить проблему под рукой - создание и разбор строки запроса - не имея двух методов составляют более чем 2 заявления? Я уверен, что вы могли бы сделать это в гораздо более элегантной манере, и я с нетерпением жду любой отзыв на моем пути!

const createQueryString = input => encodeURI(`?${Object.keys(input).map(name 
=> `${name}=${input[name]}`).join('&')}`);

const queryString = createQueryString({
  name: 'Darrell',
  age: '3     2',
  nationality: 'Swedish'
});

console.log(queryString);

const parseQueryString = (input, obj = Object.create(null)) => 
decodeURI(input.slice(input.indexOf('?') + 1, 
input.length)).split('&').map(entry => [
  [entry.split('=')[0]],
  [entry.split('=')[1]]
]).reduce((obj, query) => Object.assign(obj, {
  [query[0][0]]: query[1][0]
}), {});

const parsedQueryString = parseQueryString(queryString);

console.log(parsedQueryString);


1493
3
задан 8 февраля 2018 в 08:02 Источник Поделиться
Комментарии
3 ответа

Ну это интересный вопрос!

Я не вижу, сколько вы могли бы сделать в createQueryString помимо потенциального использования Object.entries вместо Object.keys и небольшой перестановки, чтобы избавиться от внешнего шаблона строки.

const createQueryString = input => 
'?' + encodeURI(Object.entries(input)
.map(([name, value]) => `${name}=${value}`).join('&'));

Следует отметить, что здесь есть проблема, если ваше имя или значение содержит &. Чтобы исправить это, вы должны позвонить encodeURIComponent на каждую часть, а затем отбросить внешние enocdeURI вызова.

const createQueryString = input => 
'?' + Object.entries(input)
.map(([name, value]) =>
`${encodeURIComponent(name)}=${encodeURIComponent(value)}`
).join('&');

parseQueryString можно улучшить несколькими способами.


  1. Вы не используете obj = Object.create(null)так избавиться от нее.

  2. Есть (в основном) встроенный способ сделать это, что я притворяюсь, что не существует для остальных этот пост. (Один из недостатков этого метода является то, что он требует полного URI, а не только строку запроса)

    [...new URL(uri).searchParams.entries()]
    .reduce((obj, entry) => Object.assign(obj, { [entry[0]]: entry[1] }), {})

  3. Вы можете использовать регулярные выражения, чтобы немного упростить код.

    const parseQueryString = (input) => 
    input.slice(input.indexOf('?') + 1)
    .match(/[\w\d%\-!.~'()\*]+=[\w\d%\-!.~'()\*]+/g)
    .map(s => s.split('=').map(decodeURIComponent))
    .reduce((obj, [key, value]) => Object.assign(obj, { [key]: value }), {})

Полная демо:



const createQueryString = input => 
'?' + Object.entries(input)
.map(([name, value]) =>
`${encodeURIComponent(name)}=${encodeURIComponent(value)}`
).join('&');

const queryString = createQueryString({
name: 'Darrell',
age: '3 2',
nationality: 'Swedish',
messy: '&hi=bye'
});

const parseQueryString = input =>
input.slice(input.indexOf('?') + 1)
.match(/[\w\d%\-!.~'()\*]+=[\w\d%\-!.~'()\*]+/g)
.map(s => s.split('=').map(decodeURIComponent))
.reduce((obj, [key, value]) => Object.assign(obj, { [key]: value }), {})

const parsedQueryString = parseQueryString(queryString);

console.log(parsedQueryString)




2
ответ дан 8 февраля 2018 в 10:02 Источник Поделиться

Каждый прошел через ненужных усилий построения парсера/генератора, когда современные браузеры, такие как Firefox, Chrome и Safari имеют URLSearchParams. Вот он, завернутый в указанной функции:



const createQueryString = i => (new URLSearchParams(i)).toString()
const parseQueryString = i => Array.from(new URLSearchParams(i).entries()).reduce((c, p) => (c[p[0]] = p[1], c), {})

const queryString = createQueryString({
name: 'Darrell',
age: '3 2',
nationality: 'Swedish'
});

console.log(queryString);

const parsedQueryString = parseQueryString(queryString);

console.log(parsedQueryString);



Конечно, ваш пробег может варьироваться. Если вы хотите поддержки старых браузеров, вы можете просто полифилл. Таким образом, ваш код-это перспективный, и удаление устаревших поддержки будет означать только удалением полифилл, не обновляя код.

2
ответ дан 9 февраля 2018 в 06:02 Источник Поделиться

Хорошая задача для регулярных выражений и строковых методов. Хотя я не считаю, что одно выражение может иметь запятую. (a,b) есть два выражения в моей книге, что означало бы только один аргумент в вызов функции, одна запись в массиве. Без запятой его практически невозможно?

Следующее является примером того, как не следует писать код.

e кодирование функции.
p parsing функции.

e=i=>encodeURI("?"+Object.entries(i).join('&').replace(/((^|&).*?),/g,"$1="))
p=(i,o={})=>((decodeURI(i)+"&").replace(/([^?].*?)=(.*?)&/g,(p,a,b)=>o[a]=b),o)

const queryString = e({name: "Blind",age: "5 0",nationality: 'Australian'})
const parsedString = p(queryString);

Как отметил Джозеф ответа URLSearchParams - это замечательно, но его ответ был немного раздутой и может быть упрощена

Нет необходимости toString() как он может быть преобразован с пустой строкой

const createQueryString =i=>""+new URLSearchParams(i)

И разобрать можно упростить, удалив избыточные entries звоните и создать литерал массива заполняется через spread оператора.

const parseQStr = (i,o={})=>([...new URLSearchParams(i)].forEach(v=>o[v[0]]=v[1]),o)

// or the slightly slower
const parseQStr = i=>[...new URLSearchParams(i)].reduce((o,v)=>(o[v[0]]=v[1]),o),{})

0
ответ дан 9 февраля 2018 в 01:02 Источник Поделиться