Кастинг простых объектов для экземпляров функций ( "классов" ) в javascript

function Person() {
      var self = this;

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

function Animal(){
     var self=this;

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

Ответ сервера:

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

Я получаю массив Person с сервера. Я хочу выделить общий массив Person для типированного массива Person. Поэтому я могу использовать

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

Я основал Javascript

 Object.create(Person,person1);

Но я хочу использовать кросс-браузерную версию с поддержкой массива

  ObjectArray.create(Person,persons);

или

 Object.create(Person[],persons);

Ответ 1

Создание объекта в JavaScript требует вызова его конструктора. Итак, сначала вам нужно будет найти правильные аргументы, которые не всегда могут быть просто свойствами. После этого вы можете переназначить все общедоступные свойства из объекта JSON-parsed в созданные экземпляры.

Общее решение состоит в том, что каждый конструктор принимает любые объекты, которые похожи на экземпляры (включая реальные экземпляры) и клонирует их. Вся внутренняя логика, необходимая для создания правильных экземпляров, будет расположена в нужном месте.

Или даже лучше, чем перегрузка конструктора, может заключаться в создании статического метода в вашем классе, который принимает объекты и создает экземпляры из них:

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

Ваш случай очень прост, так как у вас нет аргументов и только публичных свойств. Чтобы изменить {personName:John,animals:[]} на экземпляр объекта, используйте это:

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

Вы также можете использовать функцию Object.assign (или, например, jQuery.extend pre-ES6) для этого:

var personInstance = Object.assign(new Person(), personLiteral);

Создание экземпляров Animal аналогично.

Поскольку JSON не передает никакой информации о классах, вы должны знать структуру раньше. В вашем случае это будет:

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]);
    }
}

Кстати, ваши методы run, скорее всего, будут добавлены в объект Animal.prototype вместо каждого экземпляра.

Ответ 2

Похоже, у вас есть классы, которые имеют некоторые прототипы, и вы просто хотите, чтобы ваши объекты использовали эти методы. 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();  
});

Это может быть намного проще (и мы могли бы избежать всего копирования), если все поддерживали свойство __proto__ 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();  
});​

Ответ 3

Прежде всего: в JavaScript у вас нет классов, как в С++, Java или С#. Поэтому у вас не может быть типизированного массива.

То, что вы делаете, должно в основном работать для переменных, но не для функций. Таким образом, вам нужно будет добавить функции в первую очередь. Посмотрите на следующий код, чтобы получить представление.

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

Ответ 4

Как создать стильный метод класса Person, который примет ответ сервера и создаст требуемые переменные.

Это просто идея. Посмотрите, подходит ли это вашей проблеме.

//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 );