2009-07-05 13 views
5

Próba deserializacji danych JSON i aktualizacji prototypu każdego obiektu i dziedziczenia wspólnej funkcji.Prototyp JavaScript nieokreślony po deserializacji eval

Jednak poniższy skrypt zgłasza błąd "ludzie [0] .getFullName nie jest funkcją". Prototyp dla deserializowanych obiektów wydaje się niezdefiniowany po przypisaniu.

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

Odpowiedz

2

Obiekt prototype jest własnością konstruktorów, nie stanowi przypadkach. Co szukasz jest własnością __proto__:

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

Złą wiadomością jest to, że nie działa we wszystkich przeglądarkach. Działa w Firefoksie i Safari, nie działa w IE. Alternatywą jest użycie konstruktorów do tworzenia instancji Twoich ludzi. Niestety musisz skopiować wszystkie właściwości:

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

Pętla kopiowania właściwości na CTOR stanowi najlepsze rozwiązanie dla późnego wiązania dla tego, co próbuję wykonać. Dzięki! –

4

przedmiot x, który jest tworzony przez x = nowej osoby() jest powiązany/dziedziczy Person.prototype, ale jeśli chodzi o standard ECMA dotyczy nie można zmienić x.prototype w celu następnie zmień to połączenie/dziedziczenie, to jest "magiczna moc", która zawiera tylko jedno kluczowe słowo nowe.
Mozilla wydaje się oferować sposób na zmianę linku obiektu po utworzeniu obiektu za pomocą niestandardowej właściwości __proto__.

Mozilla-only:

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

powinien pracować w dowolnym miejscu:

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 ... dzięki za oświecenie. Występuje przykład przeglądarki oparty na argumencie danych. Będę eksperymentować z tym więcej. Dzięki! –

2

Zasadniczo trzeba uzyskać obiekt JSON do obiektu osoby, a następnie getFullName dotyczy tylko. Przerobiłem to, co trzeba było nieco popracować. Nie ma chyba nawet lepsze sposoby, ale myślę, że to, co pan zamierza zrobić ...

<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

Dzięki Tony. Używam przestrzeni nazw ASP.NET Sys.Serialization zamiast eval w produkcji. Byłby ciekawy, aby dowiedzieć się więcej o potencjalnych zagrożeniach bezpieczeństwa związanych z wysyłaniem danych JSON. –

+0

Spójrz na: 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

Jest to nieefektywne, ponieważ tworzy kopię metody dla każdej instancji. – kpozin

Powiązane problemy