2012-08-04 11 views
13
function Person() { 
     var self = this; 

     self.personName=""; 
     self.animals=[]; 
} 

function Animal(){ 
    var self=this; 

    self.animalName=""; 
    self.run=function(meters){ 
     ..... 
    } 
} 

Server Antwort:Ebene Objekte Casting Instanzen funktionieren ("Klassen") in Javascript

[{personName:John,animals:[{animalName:cheetah},{animalName:giraffe}]} , {personName:Smith,animals:[{animalName:cat},{animalName:dog}]} ] 

Ich erhalte Person Array von Server. Ich möchte generisches Person-Array in typisiertes Person-Array umwandeln. So kann ich

persons[0].Animals[2].Run(); 

gründete ich Javascripts

Object.create(Person,person1); 

Aber ich will Cross-Browser-Version davon mit Array-Unterstützung

ObjectArray.create(Person,persons); 

oder

Object.create(Person[],persons); 
+4

Ihre Frage ist unklar. JavaScript-Arrays sind nicht typisiert. (Nun, es gibt neue Array-ähnliche Dinge, die eingegeben werden, aber grundlegende Arrays sind nicht.) – Pointy

+0

Der Code, den Sie sagen möchten, impliziert, dass das Person-Array, das Sie vom Server abrufen, Objekte enthält, z. '[{Tier: [...]}, {Tier: [...]}] - meinst du das? – JMM

+0

Ich habe Beispielcode hinzugefügt. Ich denke, die Frage ist jetzt klar. – ozz

Antwort

15

ein Objekt in JavaScript zu erstellen, müssen Sie den Aufruf der Konstruktor . Also, zuerst müssen Sie die richtigen Argumente finden, die nicht immer nur Eigenschaften sind. Danach können Sie alle öffentlichen Eigenschaften des JSON-analysierten Objekts den erstellten Instanzen neu zuweisen.

Eine allgemeine Lösung wäre, dass jeder Konstruktor alle Objekte akzeptiert, die wie Instanzen aussehen (einschließlich echter Instanzen) und sie klont. Die gesamte interne Logik, die zum Erstellen der richtigen Instanzen benötigt wird, befindet sich dann an der richtigen Stelle.

Oder noch besser als der Konstruktor Überlastung könnte sein, eine statische Methode auf Ihre Klasse zu erstellen, die Objekte und erzeugt Instanzen von ihnen nimmt:

Person.fromJSON = function(obj) { 
    // custom code, as appropriate for Person instances 
    // might invoke `new Person` 
    return …; 
}; 

Ihr Fall ist sehr einfach, wie Sie don‘ t haben irgendwelche Argumente und nur öffentliche Eigenschaften.Um {personName:John,animals:[]} auf eine Objektinstanz zu ändern, verwenden diese:

var personLiteral = ... // JSON.parse("..."); 
var personInstance = new Person(); 
for (var prop in personLiteral) 
    personInstance[prop] = personLiteral[prop]; 

Sie auch Object.extend Funktionalität für diese verwenden können, sollten Sie zur Hand haben (zB jQuery):

var personInstance = $.extend(new Person(), personLiteral); 

Die Erstellung der Animal Instanzen funktioniert analog.

Da JSON keine Informationen über die Klassen transportiert, müssen Sie die Struktur vorher kennen. In Ihrem Fall wird es sein:

var persons = JSON.parse(serverResponse); 
for (var i=0; i<persons.length; i++) { 
    persons[i] = $.extend(new Person, persons[i]); 
    for (var j=0; j<persons[i].animals; j++) { 
     persons[i].animals[j] = $.extend(new Animal, persons[i].animals[j]); 
    } 
} 

Btw, scheint Ihre run Methoden wahrscheinlich auf dem Animal.prototype Objekt hinzugefügt werden, anstatt jede Instanz.

+0

vielen dank, du hast mir eine menge zeit gespart! – Tone

1

Zunächst all: In JavaScript hast du keine Klassen wie ich n C++, Java oder C#. Sie können also nicht wirklich ein typisiertes Array haben.

Was Sie tun, sollte grundsätzlich für Variablen arbeiten, aber nicht für Funktionen. Sie müssten also zuerst die Funktionen hinzufügen. Sehen Sie sich den folgenden Code an, um eine Idee zu bekommen.

<script type="text/javascript"> 

function Person() { 
     var self = this; 

     self.personName=""; 
     self.animals=[]; 
} 

function Animal(){ 
    var self=this; 

    self.animalName=""; 
    self.run=function(meters){ 
     7/... do something 
    } 
} 

var persons = [{personName:"John",animals:[{animalName:"cheetah"},{animalName:"giraffe"}]} , {personName:"Smith",animals:[{animalName:"cat"},{animalName:"dog"}]} ]; 

//use this to assign run-function 
var a = new Animal(); 

//assign run-function to received data 
persons[0].animals[0].run = a.run; 

//now this works 
persons[0].animals[0].run(); 

</script> 
+0

Zuweisen der Lauffunktion ist so interessant. Ich mochte es. – ozz

1

Wie wäre es mit dem Erstellen einer statischen Methode für die Personenklasse, die Ihre Serverantwort akzeptiert und die erforderlichen Variablen erstellt.

Dies ist nur eine Idee. Bitte sehen Sie, ob das zu Ihrem Problem passt.

//Static method 
Person.createObjects = function(response) { 
    var persons = []; 
    for (var p = 0; p < response.length; p++) { 
     //Create Person 
     var person = new Person(response[p].personName); 
     //Create Animals 
     for (var a = 0; a < response[p].animals.length; a++) { 
      var animal = new Animal(response[p].animals[a].animalName); 
      //Push this animal into Person 
      person.animals.push (animal); 
     } 
     //Push this person in persons 
     persons.push (person); 
    } 
    //Return persons 
    return persons; 
} 

//Now Create required persons by passing the server response 
var persons = Person.createObjects (response); 
+0

beheben Sie Ihre laufenden Variablen. Möchtest du 'p' oder' i' verwenden? Ich denke auch nicht, dass dies eine Staticmethode für die 'Person'-Klasse sein sollte - warum sollte man die Klasse ändern, wenn sich das JSON-Format ändert? – Bergi

+0

Danke Bergi. Ich habe meine Variable auf p aktualisiert. Und bezüglich der statischen Methode. Ja, das ist eine statische Methode in der Personenklasse. Und definitiv wird sich das JSON-Format nicht ändern. Wenn es sich ändert, wird es auf keinen Fall automatisch in das Objekt Person umgewandelt. Aus Gründen der Kompatibilität sollte das JSON-Format immer dasselbe Format haben. –

2

Es scheint, als ob Sie Klassen haben, die einige Prototyp-Methoden haben und Sie möchten nur Ihre Objekte mit diesen Methoden verwenden können. http://jsfiddle.net/6CrQL/3/

function Person() {} 

Person.prototype.speak = function() { 
    console.log("I am " + this.personName); 
}; 

Person.prototype.runAnimals = function() { 
    this.animals.each(function(animal){ 
     animal.run(); 
    }) 
}; 

function Animal() {} 

Animal.prototype.run = function() { 
    console.log("My Animal " + this.animalName+ " is running"); 
} 

var untypedPersons = [{personName:"John",animals:[{animalName:"cheetah"},{animalName:"giraffe"}]} , {personName:"Smith",animals:[{animalName:"cat"},{animalName:"dog"}]} ]; 

function fromArray(arr, constructor) { 
    return arr.map(function(obj){ 
     var typed = Object.create(constructor.prototype); 
     // Now copy properties from the given object 
     for (var prop in obj) { 
      typed[prop] = obj[prop]; 
     } 
     return typed; 
    }); 
} 

var persons = fromArray(untypedPersons, Person); 
// Attach prototype to each animals list in person 
persons.each(function(person){ 
    person.animals = fromArray(person.animals, Animal); 
}); 

persons.each(function(person){ 
    person.speak(); 
    person.runAnimals(); 
}); 

Dies alles könnte viel einfacher sein (und wir konnten alle das Kopieren vermeiden), wenn jeder die __proto__ Eigenschaft unterstützt http://jsfiddle.net/6CrQL/2/

persons.each(function(person){ 
    person.__proto__ = Person.prototype; 
    person.animals.each(function(animal){ 
    animal.__proto__ = Animal.prototype; 
    }); 
}); 

persons.each(function(person){ 
    person.speak(); 
    person.runAnimals(); 
});​ 
+0

Dies ist keine geeignete Verwendung für 'Object.create' und funktioniert auch nicht auf diese Weise. – Bergi

+0

@Bergi Ich bemerkte es, aktualisierte es mit einer neuen Lösung –

+0

Wofür ist 'surrogateConstructor' gut, können Sie nicht einfach das normale verwenden? Oder verwenden Sie 'Object.create (constructor.prototype)', wenn Sie es nicht aufrufen möchten. – Bergi