2009-07-05 13 views
5

Tentativo di deserializzare i dati JSON e aggiornare il prototipo di ciascun oggetto ed ereditare una funzione comune.Prototipo Javascript non definito dopo desalizzazione eval

Tuttavia, il seguente script genera l'errore "people [0] .getFullName non è una funzione". Il prototipo per oggetti deserializzati sembra essere indefinito dopo l'assegnazione.

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

risposta

2

La proprietà prototype è una proprietà di costruttori, non di istanze. Quello che state cercando è la proprietà __proto__:

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

La cattiva notizia è che non funziona in tutti i browser. Funziona in Firefox e Safari, non funziona in IE. Un'alternativa è usare i costruttori per istanziare la tua schiera di persone. Purtroppo dovrete copiare tutte le proprietà:

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

Il ciclo di copia delle proprietà sul CTOR fornisce la migliore soluzione tardiva per ciò che sto cercando di fare. Grazie! –

4

Un oggetto x che viene creato da x = new Person() è legata a/eredita da Person.prototype, ma per quanto riguarda lo standard ECMA è interessato non è possibile modificare x.prototype al fine di cambia quel link/eredità in seguito, questo è il "potere magico" solo la parola chiave nuova possiede.
Mozilla sembra offrire un modo per modificare il collegamento dell'oggetto dopo che un oggetto è stato creato tramite la proprietà non standard __proto__.

Mozilla-only:

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

dovrebbe funzionare ovunque:

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 ... grazie per l'illuminazione. L'esempio di cross-browser di costruzione con l'arg di dati funziona. Ne sperimenterò ancora un po '. Grazie! –

2

In sostanza, è necessario ottenere l'oggetto JSON in un oggetto persona, e poi il getFullName applica solo. Ho riscritto quello che avevi leggermente da lavorare. C'è probabilmente modi ancora migliori, ma credo che questo è quello che avevate intenzione di fare ...

<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

Grazie Tony. Sto usando ASP.NET Sys.Serialization namespace invece di eval in produzione. Sarebbe curioso di saperne di più sui potenziali rischi per la sicurezza coinvolti nell'invio di dati JSON. –

+0

Dai un'occhiata a: 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

Questo è inefficiente perché crea una copia del metodo su ogni istanza. – kpozin

Problemi correlati