Eu sei como analisar uma string JSON e transformá-lo em um objeto JavaScript. Você pode usar JSON.parse()
em navegadores modernos (e IE9 +).
Isso é ótimo, mas como posso pegar esse objeto JavaScript e transformá-lo em um objeto JavaScript específico (ou seja, com um determinado protótipo)?
Por exemplo, suponha que você tenha:
function Foo()
{
this.a = 3;
this.b = 2;
this.test = function() {return this.a*this.b;};
}
var fooObj = new Foo();
alert(fooObj.test() ); //Prints 6
var fooJSON = JSON.parse({"a":4, "b": 3});
//Something to convert fooJSON into a Foo Object
//....... (this is what I am missing)
alert(fooJSON.test() ); //Prints 12
Novamente, não estou pensando em como converter uma string JSON em um objeto JavaScript genérico. Quero saber como converter uma string JSON em um objeto "Foo". Ou seja, meu Objeto agora deve ter uma função 'test' e propriedades 'a' e 'b'.
ATUALIZAÇÃO Depois de fazer algumas pesquisas, pensei nisso ...
Object.cast = function cast(rawObj, constructor)
{
var obj = new constructor();
for(var i in rawObj)
obj[i] = rawObj[i];
return obj;
}
var fooJSON = Object.cast({"a":4, "b": 3}, Foo);
Isso vai funcionar?
ATUALIZAÇÃO maio de 2017 : A maneira "moderna" de fazer isso é via Object.assign
, mas essa função não está disponível nos navegadores Android IE 11 ou anteriores.
Respostas:
As respostas atuais contêm muitos códigos de biblioteca ou rolados à mão. Isso não é necessário.
Use
JSON.parse('{"a":1}')
para criar um objeto simples.Use uma das funções padronizadas para definir o protótipo:
Object.assign(new Foo, { a: 1 })
Object.setPrototypeOf({ a: 1 }, Foo.prototype)
fonte
Object.setPrototypeOf(...)
. developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…setPrototypeOf
ser descritores de propriedade.Veja um exemplo abaixo (este exemplo usa o objeto JSON nativo). Minhas alterações estão comentadas em CAPITALS:
fonte
for (var prop in obj) {if (obj.hasOwnProperty(prop)) {this[prop] = obj[prop];}}
for (var prop in obj) {if (this.hasOwnProperty(prop)) {this[prop] = obj[prop];}}
. Isso pressupõe que você espera do servidor para preencher todas as propriedades, IMO deve também jogar se obj.hasOwnProperty () falhar ...Deseja adicionar a funcionalidade de serialização / desserialização JSON, certo? Então veja o seguinte:
Você deseja conseguir isso:
toJson () é um método normal.
fromJson () é um método estático.
Implementação :
Uso :
Nota: Se você quiser, pode mudar todas as definições de propriedade, como
this.title
,this.author
, etc porvar title
,var author
, etc. e adicionar getters a eles para realizar a definição da UML.fonte
toJson()
método - independentemente de ter propriedades individuais codificadas ou usar um para cada um - precisará adicionar códigos de escape de barra invertida para alguns caracteres que possam estar em cada propriedade de string. (A título do livro pode ter aspas, por exemplo.)JSON.stringify()
vez de escrever para JSon (). Não há necessidade de reinventar a roda agora que todos os navegadores modernos a suportam.serializable = ['title', 'author', ...]
.JSON.stringify(serializable.reduce((obj, prop) => {...obj, [prop]: this[prop]}, {}))
Um post que achei útil: Noções básicas sobre protótipos JavaScript
Você pode mexer com a propriedade __proto__ do objeto.
Isso permite que o fooJSON herde o protótipo Foo.
Eu não acho que isso funcione no IE, no entanto ... pelo menos pelo que li.
fonte
__proto__
há muito tempo foi preterido . Além disso, por motivos de desempenho, não é recomendável modificar a propriedade interna [[Prototype]] de um objeto já criado (por configuração__proto__
ou por qualquer outro meio).[[prototype]]
e parece irrelevante no Chrome. No firefox, chamar new é mais lento do que usar prototype, e Object.create é mais rápido. Acho que o problema com o FF é que o primeiro teste é mais lento que o anterior, apenas a ordem da execução é importante. No cromo, tudo roda quase na mesma velocidade. Quero dizer acesso à propriedade e nvocation de métodos. A creatina é mais rápida com as novas, mas isso não é tão importante. Veja: jsperf.com/prototype-change-test-8874874/1 e: jsperf.com/prototype-changed-method-callObject.setPrototypeOf(fooJSON, Foo.prototype)
vez de definirfooJSON.__proto__
... certo?Estou faltando alguma coisa na pergunta ou por que mais ninguém mencionou o
reviver
parâmetro deJSON.parse
desde 2011?Aqui está o código simplista da solução que funciona: https://jsfiddle.net/Ldr2utrr/
PS: Sua pergunta é confusa: >> Isso é ótimo, mas como posso pegar esse objeto JavaScript e transformá-lo em um objeto JavaScript específico (ou seja, com um certo protótipo)? contradiz o título, onde você pergunta sobre a análise JSON, mas o parágrafo citado pergunta sobre a substituição do protótipo do objeto de tempo de execução JS.
fonte
Uma abordagem alternativa poderia estar usando
Object.create
. Como primeiro argumento, você passa o protótipo e, para o segundo, passa um mapa de nomes de propriedades para os descritores:fonte
Gosto de adicionar um argumento opcional ao construtor e da chamada
Object.assign(this, obj)
e depois manipular quaisquer propriedades que sejam objetos ou matrizes de objetos:fonte
Por uma questão de completude, eis uma simples linha que eu acabei (não precisei verificar se não há propriedades Foo):
fonte
Eu criei um pacote chamado json-dry . Ele suporta referências (circulares) e também instâncias de classe.
Você precisa definir 2 novos métodos em sua classe (
toDry
no protótipo eunDry
como método estático), registrar a classe (Dry.registerClass
) e pronto.fonte
Embora isso não seja tecnicamente o que você deseja, se você souber de antemão o tipo de objeto que deseja manipular, poderá usar os métodos de chamada / aplicação do protótipo do seu objeto conhecido.
você pode mudar isso
para isso
fonte
Combinei as soluções que consegui encontrar e compilei em uma genérica que pode analisar automaticamente um objeto personalizado e todos os seus campos recursivamente, para que você possa usar métodos de protótipo após a desserialização.
Uma suposição é que você definiu um arquivo especial que indica seu tipo em cada objeto que você deseja aplicá-lo automaticamente (
this.__type
no exemplo).uso:
Função de atribuição de tipo (funciona recursivamente para atribuir tipos a qualquer objeto aninhado; também itera através de matrizes para encontrar objetos adequados):
fonte
A resposta atualmente aceita não estava funcionando para mim. Você precisa usar Object.assign () corretamente:
Você cria objetos desta classe normalmente:
Se você possui uma string json, precisa analisar na classe Person, faça o seguinte:
fonte
As respostas de Olivers são muito claras, mas se você está procurando uma solução em js angulares, escrevi um bom módulo chamado Angular-jsClass que facilita isso, pois ter objetos definidos em notação litaral é sempre ruim quando você está visando um grande projeto mas dizendo que os desenvolvedores enfrentam um problema que exatamente o BMiner disse, como serializar um json para criar objetos de notação de protótipo ou construtor
https://github.com/imalhasaranga/Angular-JSClass
fonte