String de escape no contexto eval com JSON.stringify

Nov 13 2020

Em primeiro lugar: eu sei que há muitas perguntas relacionadas à fuga, mas não encontrei uma resposta geral que funcione até agora. Digamos que eu tenha esta função simples de brinquedo para demonstração:

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

Dado um literal de objeto como {a: 1, b: "c"}(um POJO), fdeve retornar um "clone" dele. (Observe que eu realmente não uso essa abordagem para clonagem ou similar, e estou ciente de que isso evalé mau e também nem mesmo é necessário aqui, é apenas para demonstração do problema de escape!)

Isso funciona bem, mas apenas enquanto os valores POJO não contiverem a '. Agora é claro que eu poderia escapar do JSON usando algo como JSON.stringify(somePOJO).replace(/'/g, "\\'"). Isso funciona se os valores POJO contiverem ', mas não se contiverem \\'. E isso cria uma espiral de fuga ...

Existe alguma solução para isso?

Respostas

1 traktor Nov 13 2020 at 14:01

A função de escape para preservar uma string JSON por meio de ser avaliada pela evalfunção, o compilador JavaScript em algumas circunstâncias ou pela JSON.parsefunção é realmente JSON.stringify. Este JSONmétodo irá felizmente stringificar valores de string, não apenas tipos de dados de objetos.

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);

O motivo pelo qual não faz parte da escape/encodeURI/encodeURIComponentfamília de funções é que são para caracteres de escape para inclusão em URLs, enquanto este caso é sobre caracteres de escape a serem analisados ​​por um analisador JavaScipt.

Na maioria dos casos, principalmente para analisar texto JSON usando JSON.parse, stringificar o texto JSON uma segunda vez e analisá-lo duas vezes é simplesmente desnecessário.

De interesse um tanto acadêmico agora, mas antes da introdução do JSONem Javascript, pode-se restringir uma string inspecionando serialmente seus caracteres e barras invertidas que escapam, pelo menos um tipo de aspas e códigos de controle de escape Unicode - a pergunta postada pode estar faltando a parte sobre a necessidade de escapar caracteres de barra invertida, bem como aspas.