
JSON.stringify é um método frequentemente usado no desenvolvimento diário. Você pode realmente usá-lo com flexibilidade?
Antes de estudar este artigo, Xiaobao deseja que todos respondam a algumas perguntas e aprendam stringify em profundidade.
stringify possui vários parâmetros. Qual é a utilidade de cada parâmetro?stringify null、undefined、NaN ?ES6 Haverá tratamento especial durante o processo de serialização do tipo Symbol e BigIntstringifystringify não é adequado para cópia profunda? pode deixar uma impressão primeiro.

Na programação diária, costumamos usar o método JSON.stringify para converter um objeto em um formato de string JSON .
const stu = {
nome: 'zcxiaobao',
idade: 18
}
// {"nome":"zcxiaobao","idade":18}
console.log(JSON.stringify(stu)); Mas stringify é realmente tão simples? Vamos primeiro dar uma olhada na definição de stringify no MDN .
Estados MDN: O método JSON.stringify() converte um objeto ou valor JavaScript em JSON . Se uma função replacer for especificada, o valor pode ser opcionalmente substituído ou o replacer especificado é uma matriz. .
Depois de ler a definição, Xiaobao ficou surpreso. stringfy tem mais de um parâmetro? Claro, stringify tem três parâmetros.
Vamos dar uma olhada na sintaxe stringify e na introdução dos parâmetros:
JSON.stringify(value[, replacer [, space]])
value : O valor a ser sequenciado em uma string JSON.replacer (opcional) Se o parâmetro for uma função , durante o processo de serialização, cada atributo do valor serializado será convertido e processado pela função;
se o parâmetro for um array , apenas as propriedades contidas neste array serão Somente o atributo; os nomes serão serializados na string JSON final.
Se este parâmetro for null ou não fornecido, todos os atributos do objeto serão serializados.
space (opcional): especifica a string de espaço em branco usada para recuo, usada para embelezar a saída. Se o parâmetro for um número, ele representa o número de espaços. O limite superior é 10.
Se o valor for menor que 1, significa que não há espaços.
Se o parâmetro for uma string (quando o comprimento da string exceder 10 letras, as primeiras 10 letras serão consideradas), a string será tratada como espaços
. o parâmetro não é fornecido (ou é nulo), não haverá espaços
replacer
replacer como função
replacer como função, possui dois parâmetros, chave ( key ) e valor ( value ), e ambos os parâmetros serão serializados.
No início, a função de substituição será passada em uma string vazia como valor-chave, representando o objeto a ser stringificado . É importante entender isso. A função replacer não analisa o objeto em pares de valores-chave quando ele surge, mas primeiro passa o objeto a ser serializado . Em seguida, as propriedades de cada objeto ou array são passadas sequencialmente. Se o valor de retorno da função for indefinido ou função, o valor do atributo será filtrado e o restante seguirá as regras de retorno.
//repalcer aceita valor-chave de dois parâmetros
// valor-chave é cada par de valores-chave do objeto // então podemos simplesmente filtrar com base no tipo de chave ou valor function replacer(key, value) {
if (tipo de valor === "string") {
retornar indefinido;
}
valor de retorno;
}
// a função pode testar a função sozinha replacerFunc(key, value) {
if (tipo de valor === "string") {
retornar() => {};
}
valor de retorno;
}
const foo = {fundação: "Mozilla", modelo: "caixa", semana: 45, transporte: "carro", mês: 7};
const jsonString = JSON.stringify(foo, replacer); JSON é {"week":45,"month":7}
mas se a serialização for uma matriz, se replacer retornar undefined ou função, o valor atual não será ignorado e será substituído por null .
lista const = [1, '22', 3] const jsonString = JSON.stringify(list, replacer)
O resultado da serialização JSON é '[1,null,3]'
replacer
é mais fácil de entender como um array, filtrando os valores-chave que aparecem no array.
const foo = {fundação: "Mozilla", modelo: "caixa", semana: 45, transporte: "carro", mês: 7};
const jsonString = JSON.stringify(foo, ['week', 'month']); O resultado da serialização JSON é {"week":45,"month":7} , e apenas week e month são retido.
undefined
undefined e valores Symbol serão ignorados durante o processo de serialização.
e os valores Symbol serão ignorados. Quando convertido
apenas para nulo: indefinido será retornado
// 1. A existência desses três valores no valor do atributo do objeto será ignorada const obj = {
nome: 'zc',
idade: 18,
// A função será ignorada sayHello() {
console.log('olá mundo')
},
// indefinido será ignorado esposa: indefinido,
// O valor do símbolo será ignorado id: Symbol(111),
// [Símbolo('zc')]: 'zc',
}
// Resultado de saída: {"name":"zc","age":18}
console.log(JSON.stringify(obj));
// 2. Esses três valores no array serão convertidos em nulos
lista constante = [
'zc',
18,
//Função convertida para nula
function digaOlá() {
console.log('olá mundo')
},
// indefinido convertido em nulo
indefinido,
//Símbolo convertido para nulo
Símbolo(111)
]
// ["zc",18,nulo,nulo,nulo]
console.log(JSON.stringify(lista))
// 3. A conversão separada desses três valores retornará indefinido
console.log(JSON.stringify(indefinido)) // indefinido
console.log(JSON.stringify(Symbol(111))) // indefinido
console.log(JSON.stringify(função dizerOlá() {
console.log('olá mundo')
})) // converte o valor Se houver toJSON() (), qualquer valor toJSON() retornar será o valor retornado pelo resultado da serialização, e os outros valores serão. ignorado.
const obj={
nome: 'zc',
paraJSON(){
retornar 'retornar para JSON'
}
}
//volta para JSON
console.log(JSON.stringify(obj)); valores booleanos, números e strings será automaticamente convertido no valor original JSON durante o processo de serialização.
.stringify([novo Número(1), new String("zcxiaobao"), novo Boolean(true)]);
// [1,"zcxiaobao",true] O recurso quatro visa principalmente valores especiais em JavaScript , como NaN , Infinity e null no tipo Number . Esses três tipos de valores serão tratados como null durante a serialização .
// [nulo,nulo,nulo,nulo,nulo]
JSON.stringify([nulo, NaN, -NaN, Infinito, -Infinity])
// O recurso 3 mencionou que os objetos de empacotamento de valores booleanos, números e strings serão automaticamente convertidos nos valores originais correspondentes durante o processo de serialização // A conversão de tipo implícita chamará a classe de empacotamento, então Number => NaN será chamado primeiro
// Depois converte para nulo
// 1/0 => Infinito => nulo
JSON.stringify([Number('123a'), +'123a', 1/0]) O método toJSON (igual a Date.toISOString() ) é implantado no objeto Date para convertê-lo em um string, então JSON.stringify() serializará o valor Date em uma string de formato de hora .
// "2022-03-06T08:24:56.138Z" JSON.stringify(new Date())
Ao mencionar o recurso Símbolo, quando Symbol é usado como um valor, objetos, matrizes e usos individuais serão ignorados, convertidos em null e convertidos em undefined respectivamente.
Da mesma forma, todas as propriedades com Símbolo como chave de propriedade serão completamente ignoradas, mesmo que sejam forçadas a serem incluídas no parâmetro substituto .
const obj={
nome: 'zcxiaobao',
idade: 18,
[Símbolo('lyl')]: 'único'
}
função substituto(chave, valor) {
if (typeof chave === 'símbolo') {
valor de retorno;
}
}
// indefinido
JSON.stringify(obj, replacer); No caso acima, podemos ver que, embora especifiquemos à força o valor do tipo Symbol de retorno por meio de replacer , ele eventualmente será ignorado.
JSON.stringify estipula: Tentar converter um valor do tipo BigInt gerará TypeError
const bigNumber = BigInt(1) // TypeError não capturado: não sei como serializar um BigInt Console.log(JSON.stringify(bigNumber))
O recurso 8 aponta: Executar este método em objetos contendo referências circulares (objetos referem-se uns aos outros, formando um loop infinito) gerará um erro
. A maneira mais simples e violenta é usar JSON.parse(JSON.stringify(obj)) , mas a cópia profunda nesse método tem grandes armadilhas. O principal problema é que stringify não consegue lidar com o problema de referência circular.
const obj={
nome: 'zcxiaobao',
idade: 18,
}
const loopObj = {
obj
}
// Forme uma referência circular obj.loopObj = loopObj;
JSON.stringify(obj)
/* TypeError não capturado: convertendo estrutura circular em JSON
-> começando no objeto com o construtor 'Object'
| propriedade 'loopObj' -> objeto com construtor 'Object'
--- propriedade 'obj' fecha o círculo
em JSON.stringify (<anônimo>)
em <anônimo>:10:6
*/ a serialização de propriedades enumeráveis para objetos (incluindo Map/Set/WeakMap/WeakSet ), além de algumas das situações mencionadas acima, stringify também estipula claramente que apenas propriedades enumeráveis serão serializadas
// Não enumerável propriedades serão ignoradas por padrão // {"age":18}
JSON.stringify(
Objeto.criar(
nulo,
{
nome: {valor: 'zcxiaobao', enumerável: falso},
idade: {valor: 18, enumerável: verdadeiro}
}
)
); O objeto localStorage é usado para salvar os dados de todo o site por um longo tempo. Os dados salvos não têm prazo de validade até serem excluídos manualmente. Normalmente armazenamos na forma de objetos.
Basta chamar o método do objeto localStorage
const obj = {
nome: 'zcxiaobao',
idade: 18
}
//Basta chamar localStorage.setItem()
localStorage.setItem('zc', obj);
//O resultado final do retorno é [object Object]
// Pode-se observar que a simples chamada de localStorage falha console.log(localStorage.getItem('zc')) localStorage coopera com JSON.stringify
localStorage.setItem('zc', JSON.stringify(obj));
//O resultado final do retorno é {nome: 'zcxiaobao', idade: 18}
Console.log(JSON.parse(localStorage.getItem('zc'))) assume tal cenário. O backend retorna um objeto longo com muitos atributos, e precisamos apenas de alguns deles e precisamos armazená-los. atributos em localStorage .
Opção 1: Desestruturação de atribuição + stringify
// Precisamos apenas dos atributos a, e, f const obj = {
a:1, b:2, c:3, d:4, e:5, f:6, g:7
}
// Desestruturando atribuição const {a,e,f} = obj;
// Armazena em localStorage
localStorage.setItem('zc', JSON.stringify({a,e,f}))
// {"a":1,"e":5,"f":6}
console.log(localStorage.getItem('zc')) usa o parâmetro replacer de stringify
// Use o substituto para filtrar como uma matriz localStorage.setItem('zc', JSON.stringify(obj, ['a','e' , 'f']))
// {"a":1,"e":5,"f":6}
console.log(localStorage.getItem('zc')) Quando replacer é um array, podemos simplesmente filtrar os atributos que precisamos, o que é um bom truque.
Usar JSON.parse(JSON.stringify) é uma das maneiras mais simples e violentas de implementar cópias profundas de objetos. Mas, como diz o título, usar esse método de cópia profunda requer uma consideração cuidadosa.
Problema de referência circular, stringify reportará
função de erro, undefined , Symbol será ignorado,
NaN , Infinity e -Infinity serão serializados em null
...
Portanto, ao usar JSON.parse(JSON.stringify) para fazer cópia profunda, você deve pense com cuidado. Se não houver perigos ocultos mencionados acima, JSON.parse(JSON.stringify) é uma solução viável de cópia profunda.
Ao programar com arrays, geralmente usamos a função map . Com o parâmetro replacer , podemos usar este parâmetro para implementar a função map do objeto.
const ObjectMap = (obj, fn) => {
if (typeof fn! == "função") {
throw new TypeError(`${fn} não é uma função!`);
}
// Primeiro chame JSON.stringify(obj, replacer) para implementar a função de mapa // Em seguida, chame JSON.parse para reconvertê-lo em um objeto return JSON.parse(JSON.stringify(obj, fn));
};
// Por exemplo, o seguinte multiplica o valor do atributo do objeto obj por 2
const obj={
um: 1,
b: 2,
c: 3
}
console.log(ObjectMap(obj, (chave, val) => {
if (tipo de valor === "número") {
valor de retorno * 2;
}
valor de retorno;
})) Muitos estudantes podem estar se perguntando por que é necessário um julgamento adicional. Não é possível return value * 2 ?
Conforme mencionado acima, replacer passa primeiro o objeto a ser serializado. O objeto * 2 => NaN => toJSON(NaN) => undefined => é ignorado e não haverá análise subsequente de pares de valores-chave.
Com a função replacer , também podemos excluir certos atributos do objeto.
const obj={
nome: 'zcxiaobao',
idade: 18
}
// {"idade":18}
JSON.stringify(obj, (chave, val) => {
// Quando o valor de retorno for indefinido, esta propriedade será ignorada if (key === 'name') {
retornar indefinido;
}
valor de retorno;
}) JSON.stringify pode serializar objetos em strings, para que possamos usar métodos de string para implementar julgamentos simples de igualdade de objetos.
//Determina se o array contém um objeto constnames = [
{nome:'zcxiaobao'},
{nome:'txtx'},
{nome:'meu'},
];
const zcxiaobao = {nome:'zcxiaobao'};
// verdadeiro
JSON.stringify(nomes).inclui(JSON.stringify(zcxiaobao))
// Determina se os objetos são iguais const d1 = {type: 'div'}
const d2 = {tipo: 'div'}
// verdadeiro
JSON.stringify(d1) === JSON.stringify(d2); Com a ajuda das ideias acima, também podemos obter desduplicação simples de objeto array.
Mas como os resultados da serialização JSON.stringify {x:1, y:1} e {y:1, x:1} são diferentes, precisamos processar os objetos no array antes de começar.
Método 1: organize as chaves de cada objeto na matriz na ordem do dicionário
arr.forEach(item => {
const novoItem = {};
Object.keys(item) // Obtém a chave do objeto value.sort() // Valor da chave sorting.map(key => { // Gera novo objeto newItem[key] = item[key];
})
// Use newItem para realizar a operação de desduplicação}) Mas o método um é um pouco complicado. JSON.stringify fornece replacer , que pode filtrar o array.
Método 2: replacer
a função de formato de matriz de substituição unique(arr) {
const keySet=new Set();
const únicoObj = {}
// Extrai todas as chaves arr.forEach(item => {
Object.keys(item).forEach(chave => keySet.add(chave))
})
const substituto = [...keySet];
arr.forEach(item => {
// Todos os objetos são filtrados de acordo com o valor-chave especificado replacer unique[JSON.stringify(item, replacer)] = item;
})
retornar Object.keys(unique).map(u => JSON.parse(u))
}
//Teste único([{}, {},
{x:1},
{x:1},
{a:1},
{x:1,a:1},
{x:1,a:1},
{x:1,a:1,b:1}
])
// Retorna o resultado [{},{"x":1},{"a":1},{"x":1,"a":1},{"x":1,"a":1 ,"b":1}]