Строка escape в контексте eval с помощью JSON.stringify

Nov 13 2020

Прежде всего: я знаю, что есть много вопросов, связанных с побегом, но я пока не нашел в целом рабочего ответа. Скажем, у меня есть эта простая игрушечная функция для демонстрации:

function f(somePOJO) {
  var s = eval("'" + JSON.stringify(somePOJO) + "';"); // for demonstration only
  return JSON.parse(s);
}
const clone = f({a: 1, b: "c"});

Учитывая литерал объекта, такой как {a: 1, b: "c"}(POJO), fдолжен возвращать его "клон". (Обратите внимание, что я на самом деле не использую этот подход для клонирования или подобного, и я знаю, что evalэто зло, а также то, что здесь он даже не нужен, это просто для демонстрации проблемы с побегом!)

Это работает нормально, но только до тех пор, пока значения POJO не содержат '. Теперь, конечно, я мог бы избежать JSON, используя что-то вроде JSON.stringify(somePOJO).replace(/'/g, "\\'"). Это работает, если значения POJO содержат ', но не содержат \\'. И это создает спираль бегства ...

Есть ли вообще решение этой проблемы?

Ответы

1 traktor Nov 13 2020 at 14:01

Функция escape для сохранения строки JSON путем ее оценки evalфункцией, компилятором JavaScript при некоторых обстоятельствах или самой JSON.parseфункцией JSON.stringify. Этот JSONметод успешно преобразовывает строковые значения, а не только типы данных объекта.

function f(somePOJO) {
  var s = eval( JSON.stringify(JSON.stringify(somePOJO)) );
  return JSON.parse(s);
}
const obj = {a: 1, b: "c", d: "back\\, forward/"}
const clone = f(obj);
console.log(obj);
console.log(clone);

Причина, по которой он не входит в escape/encodeURI/encodeURIComponentсемейство функций, заключается в том, что они предназначены для экранирования символов для включения в URL-адреса, тогда как в данном случае речь идет об экранировании символов, которые должны быть проанализированы парсером JavaScipt.

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

В настоящее время представляет некоторый академический интерес, но до введения JSONв Javascript можно было преобразовать строку в строку, последовательно проверяя ее символы и обратную косую черту, избегая обратной косой черты, по крайней мере, один вид кавычек и управляющих кодов с экранированием Unicode - в опубликованном вопросе может отсутствовать часть о необходимости экранировать символы обратной косой черты, а также кавычки.