2009-07-05 6 views
5

Tenter de désérialiser les données JSON et mettre à jour le prototype de chaque objet et hériter d'une fonction commune. Toutefois, le script suivant génère une erreur "people [0] .getFullName n'est pas une fonction". Le prototype des objets désérialisés semble être indéfini après l'affectation.Prototype Javascript non défini après la désérialisation d'eval

<html> 
<head> 
<script> 
var json = '[ {"firstName": "John", "lastName": "Smith"}, {"firstName": "Nancy", "lastName": "Jones"} ]'; 
var people; 
eval('people = ' + json); 

function Person() { } 

Person.prototype.getFullName = function() { 
    return this.firstName + ' ' + this.lastName; 
} 

//assign prototype 
for(var i=0; i < people.length; i++){ 
    people[i].prototype = new Person(); 
} 


if(people[0].getFullName() !== 'John Smith') 
    alert('Expected fullname to be John Smith but was ' + people[0].getFullName()); 
</script> 
</head> 
</html> 

Répondre

2

La propriété prototype est une propriété de constructeurs, pas de cas. Ce que vous cherchez est la propriété __proto__:

people[i].__proto__ = new Person(); 

Les mauvaises nouvelles sont que cela ne fonctionne pas dans tous les navigateurs. Cela fonctionne dans Firefox et Safari, cela ne fonctionne pas dans IE. Une alternative consiste à utiliser des constructeurs pour instancier votre tableau de personnes. Malheureusement, vous devrez copier toutes les propriétés:

function Person(obj) { 
    for (var property in obj) { 
     this[property] = obj[property]; 
    } 
    return this; 
} 
Person.prototype.getFullName = function() { 
    return this.firstName + ' ' + this.lastName; 
} 

var people; 
eval('people = ' + json); 
for(var i=0; i < people.length; i++) { 
    people[i] = new Person(people[i]); 
} 
+0

La boucle de copie de propriété sur le CTOR fournit la meilleure solution en retard pour ce que j'essaie de faire. THX! –

4

Un objet x qui est créé par x = nouvelle personne() est lié à/hérite de Person.prototype, mais aussi loin que la norme ECMA est concerné, vous ne pouvez pas changer x.prototype pour changer ce lien/héritage par la suite, c'est le "pouvoir magique" que le nouveau mot-clé possède .
Mozilla semble offrir un moyen de modifier le lien d'objet après la création d'un objet via la propriété non standard __proto__.

Mozilla uniquement:

//assign prototype 
for(var i=0; i < people.length; i++){ 
    people[i].__proto__ = Person.prototype; 
} 

devrait fonctionner partout:

function Person(data) { this.data = data; } 
Person.prototype.getFullName = function() { 
    return this.data.firstName + ' ' + this.data.lastName; 
} 

eval('people = ' + json); 
//assign prototype 
for(var i=0; i < people.length; i++){ 
    people[i] = new Person(people[i]); 
} 
+0

Ahhh ... merci pour l'illumination. L'exemple de construction croisée avec l'argument de données fonctionne. Je vais expérimenter avec un peu plus. THX! –

2

Fondamentalement, vous devez obtenir l'objet JSON dans un objet Personne, puis le getFullName applique juste. J'ai réécrit ce que tu avais un peu de travail. Il y a probablement de meilleurs moyens, mais je pense que c'est ce que vous aviez l'intention de le faire ...

<html> 
<head> 
<script> 
//NOTE: Sending around JSON arrays leaves bad security holes for non-IE browsers (__defineSetter__) 
var json = '[ {"firstName": "John", "lastName": "Smith"}, {"firstName": "Nancy", "lastName": "Jones"} ]'; 
//Persons is just a temporary JSON array 
var persons = eval(json); 

//constructor takes optional object instance and copies all properties if it gets one 
function Person(person) { 
    if (person) { 
     for(var prop in person) 
     this[prop] = person[prop]; 
    } 
} 

//Prototype applies to all Person objects 
Person.prototype.getFullName = function() { 
    return this.firstName + ' ' + this.lastName; 
} 

//Create People array 
var people = new Array(); 
for(var i=0; i < persons.length; i++){ 
    people[i] = new Person(persons[i]); 
} 

//Now do your check 
if(people[0].getFullName() !== 'John Smith') 
    alert('Expected fullname to be John Smith but was ' + people[0].getFullName()); 

</script> 
</head> 
</html> 
+0

Merci Tony. J'utilise ASP.NET Sys.Serialization namespace au lieu d'eval en production. Serait curieux d'en savoir plus sur les risques de sécurité potentiels impliquant l'envoi de données JSON. –

+0

Jetez un oeil à: http://haacked.com/archive/2009/06/25/json-hijacking.aspx –

2
for(var i=0; i < people.length; i++){ 
     people[i].getFullName = Person.prototype.getFullName; } 
+0

Ceci est inefficace car il crée une copie de la méthode sur chaque instance. – kpozin

Questions connexes