ООП в Java Script (4): Наследование классов

Основные принципы наследования классов:

  1. Подкласс всегда наследует все свойства и методы, определенные в его надклассе.
  2. Подкласс может переопределять наследуемые свойства и методы, а также создавать новые — и это никак не должно отражаться на одноименных свойствах и методах надкласса.
  3. Подкласс должен иметь возможность вызывать родные методы надкласса даже в том случае, если переопределяет их.
  4. Объекты подкласса должны инициализироваться только в момент своего создания.

В JavaScript нет инструментов для создания классического наследования классов. Вместо этого есть наследование на основе свойства .prototype объекта: при вызове метода объекта, интерпретатор ищет этот метод в свойствах самого объекта, и если он не находит метод там, то продолжает поиск в свойстве (объекте) .prototype функции-конструтора данного объекта.

Зная о таком поведении JavaScript, попробуем создать наследование двух классов:

var Class = function(){ // функция-конструткор класса
this.className = 'Class';
}
Class.prototype.method = function(){ // описываем открытый метод класса
alert('method of ' + this.className);
}

var ClassSub = function(){ // функция-конструткор подкласса
this.className = 'ClassSub';
}
ClassSub.prototype = new Class(); // создаем объект надкласса в .prototype подкласса

var objSub = new ClassSub(); // создаем экземпляр класса ClassSub
objSub.method(); // работает! выводит 'method of ClassSub'

Видим, что подкласс унаследовал метод .method своего надкласса (выполняет его, как свой собственный). Как это происходит? Сначала интерпретатор ищет метод .method в самом объекте objSub и естественно не находит его там. Далее, интерпретатор обращается к ClassSub.prototype и ищет .method среди свойств этого объекта. Опять же — ничего не находит: мы нигде не задавали ничего похожего на ClassSub.prototype.method = function(){}. Но ведь сам объект ClassSub.prototype создан из функции-конструтора Class(). Поэтому, не найдя нужных свойств в самом ClassSub.prototype, интерпретатор обращается к .prototype функции-конструтора этого объекта. И уже здесь находит запрашиваемый метод: Class.prototype.method = function(){}.

Подтврдим это длинное рассуждение простым сравнением:

// .method объекта objSub вытаскивается из .method объекта ClassSub.prototype
alert(objSub.method == ClassSub.prototype.method); // true

// а .method объекта ClassSub.prototype вытаскивается из .method объекта Class.prototype
alert(ClassSub.prototype.method == Class.prototype.method); // true

Подобная цепочка прототипов может быть сколь угодно длинной, но поиск интепретатора в любом случае закончится в тот момент, когда он доберется до объета, созданного (явно или неявно) из встроенного класса Object. Если в Object.prototype он и теперь не найдет запрашиваемого метода, то вернет ошибку. Класс Object лежит в самом верху любой возможной иерархии классов, создаваемых в JavaScript.

Теперь попробуем переопределить этот унаследованный метод, а заодно расширить подкласс собственным дополнительным методом. Одновременно проверим, что методы надкласса отсались прежними (помним, что открытые методы и свойства можно добавлять даже после создания экземпляра класса):

ClassSub.prototype.method = function(){ // переопределяем унаследованный метод надкласса
alert('method of ' + this.className + ' but new one');
}
ClassSub.prototype.methodSub = function(){ // создаем новый метод подкласса
alert('methodSub of ' + this.className);
};

// вызываем переопределенный метод в объекте подкласса
objSub.method(); // выводит 'method of ClassSub but new one'

// вызываем новый метод в объекте подкласса
objSub.methodSub(); // выводит 'methodSub of ClassSub'

var obj = new Class(); // создаем экземпляр класса Class

// вызываем переопределенный метод в объекте надкласса
obj.method(); // выводит 'method of Class'

// вызываем новый метод в объекте надкласса
obj.methodSub(); // выводит ошибку 'obj.methodSub is not a function'

Итак, пока все идет нормально. Мы переопределили метод .method в подклассе, и экземпляр подкласса стал выполнять именно его. Одновремнно, экземпляр надкласса сохранил свой прежний одноименный метод. Мы создали новый метод подкласса, который успешно работает в экземпляре подкласса. При этом этот новый метод не стал методом надкласса - экземпляр надкласса не видит его и выдает ошибку.

Все выглядит просто до тех пор, пока мы не попробуем написать более реалистичный код. Как правило, функция-конструктор не только определяет свойства объекта, но также, выполняет некоторые инициализирующие функции. Например, создадим класс Animal, в который в качестве параметра будет передаваться имя особи, и каждый новый экземпляр которого будет кричать при рождении (=

var Animal = function(name){
this.name = name;
this.cry(); // при рождении особь должна крикнуть
}
Animal.prototype.cry = function(){
alert('whoa!');
}

var animal_thing = new Animal('karaboz'); // кричит 'whoa!';

Теперь создадим подкласс Cat, экземпляры которого не кричат, а мяучат:

var Cat = function(name){
this.name = name;
this.cry();
}
Cat.prototype = new Animal(); // наследуем от класса Animal
Cat.prototype.cry = function(){ // переопределяем метод .cry
alert('meow!');
}
var cat_thing = new Cat('mertas');

Запустив этот код, мы услышим не два крика (whoa!, meow!), а три! (whoa! ,whoa!, meow!) И понятно почему. Воторой крик происходит в тот самый момент, когда мы делаем наследование Cat.prototype = new Animal(). Мы невольно создаем экземпляр класса Animal (и заставляем его кричать при рождении). Т.е. мы запускаем функцию-конструктор надкласса вхолостую еще до создания какого-либо экземпляра подкласса!

Кроме того, в подклассе мы полностью продублировали функцию-конструктор надкласса! Пока мы даже не видим, как иначе можно заставить подкласс присваивать объекту свойства, переданные через параметры функции-конструктора, и как по-другому заставить этот конструктор что-то делать вообще.

Решение проблемы холостого вызова функции-конструктора надкласса

Может попробовать не создавать экземпляр класса Animal, а просто указать на равенство прототипов двух классов? (ведь именно через свои прототипы они и связываются). Попробуем поменять эту строчку:

Cat.prototype = Animal.prototype;

Запустив код, услышим два ожидаемых крика! Но это только кажется, что проблема решена. Попробуем сразу после создания экземпляра подкласса Cat создать еще один экземпляр надкласса Animal

var animal_thing_new = new Animal('juks');
// кричит 'meow!', но это же не экземпляр Cat!

Этот экземпляр кричит голосом класса Cat! Получилось, что мы перезаписали одноименный метод родительского класса. Все дело в том, что когда мы пишем Cat.prototype = Animal.prototype, мы передаем объекту Cat.prototype объект Animal.prototype по ссылке (как всегда происходит, когда переменной присваивается объект). Поэтому любые изменеия первого небезосновательно ведут к изменению второго. Кoгда же мы писали Cat.prototype = new Animal(), мы создавали в Cat.prototype новый объект. Меняя его свойства, мы никак не затрагивали свойства .prototype самой функции-конструктора объекта.

Попробуем реализовать наследование - без создания экземпляра родительского класса - несколько иначе. Попробуем просто скопировать в .prototype подкласса все свойства и методы из .prototype надкласса. Перепишем проблемную строчку следующим образом:

for (var prop in Animal.prototype){
Cat.prototype[prop] = Animal.prototype[prop];
}

Запустим код и увидим, что третья особь уже больше не мяучит, т.е. метод родительского класса отсался прежним! Но хорошо ли мы поступили? На самом деле, мы не унаследовали свойства надкласса, а просто создали еще одну их копию. Если объектов подкласса будет много - то для каждого объекта будет создана собственная полная копия всех свойств надкласса. Более того, если попытаться поменять методы класса после создания объектов подкласса, то эти изменеия никак не отразятся на объектах подкласса! Такой код кажется очень негибким и громоздким.

Прибегнем к следующему хитрому приему: создадим в .prototype подкласса новый объект, обладающий ссылкой на .prototype надкласса, но при этом не запускающий функцию-конструктор надкласса. Перепишем сложную строчку еще раз:

var Empty = function(){}; // создаем пустую функцию-конструтор
Empty.prototype = Animal.prototype;
Cat.prototype = new Empty();

Мы создали в Cat.prototype объект искусственного класса Empty. При создании этого объекта ничего не происходит, потому что функция-конструтор Empty() пуста. Любые присваивания в Cat.prototype будут касаться только изменения свойств самого объекта Cat.prototype и не будут затрагивать функцию-конструтор надкласса Animal. Если интепретатор не найдет требуемого метода ни в экземпляре класса Cat, ни в свойствах Cat.prototype, он обратится к функции-конструтору объекта Cat.prototype (== new Empty()) и начнет искать в Empty.prototype, который ссылается напрямую на нужный нам Animal.prototype

Решение проблемы дублирования функции-конструктора надкласса

Нам бы хотелось сделать примерно следующее:

var Cat = function(name){
Animal.apply(this, arguments);
}

Т.е. при инициализации каждого нового объекта подкласса Cat вызывать функцию-конструктор надкласса Animal в контексте объекта new Cat(). В принципе, наш код уже хорошо работает, но хотелось бы видеть его более универсальным - не привязанным к конкретным именам классов.

Сделаем одно лирическре отступление. Как мы помним, при создании любого объекта, у него образуется свойсво .constructor, берущееся из .prototype.constructor породившей его функции-конструктора. Однако, когда мы записали: Cat.prototype = new Empty(), мы создали в Cat.prototype новый объект. Если теперь попробовать обратиться к (new Cat()).constructor, интепретатор пойдет искать его в Cat.prototype.constructor, а значит в (new Empty().constructor) и найдет в результате это свойство в Empty.prototype.constructor ( == Animal.prototype.constructor). Т.е. наше свойство .constructor указывает теперь на функцию-конструктор надкласса, а не подкласса! Мы исковеркали это свойство. Зная все это, прямо сейчас можно было бы записать:

var Cat = function(name){
this.constructor.apply(this, arguments);
}

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

var Empty = function(){}; // создаем пустую функцию-конструтор
Empty.prototype = Animal.prototype;
Cat.prototype = new Empty();
Cat.prototype.constructor = Cat; // возвращаем ссылку на подлинную функцию-конструктор
Cat.superClass = Animal; // создаем ссылку на функцию-конструктор надкласса

В итоге, имеем следующий код нашей функции-конструктора подкласса:

var Cat = function(name){
Cat.superClass.apply(this, arguments);
}

Если нам теперь захочется в подклассе поменять наш метод не целиком, а только расширить его, мы можем легко сделать это так:

Cat.prototype.cry = function(){
Cat.superClass.prototype.cry.apply(this, arguments);
alert('one more cat was born');
}

Наведем порядок в нашем коде и напишем универсальную функцию наследования. Запишем ее в .prototype встроенной функции-конструткора Function. Таким образом, мы создадим новый метод для всех возможных функций, в т.ч. и для наших пользовательских классов.

// Универсальная функция наследования
Function.prototype.inheritsFrom = function(superClass) {
var Inheritance = function(){};
Inheritance.prototype = superClass.prototype;

this.prototype = new Inheritance();
this.prototype.constructor = this;
this.superClass = superClass;
}

// функция-конструктор класса
var Class = function(){}

// описание свойств и методов класса
Class.prototype.method = function(){};

// функция-конструктор подкласса
var ClassSub = function(){
ClassSub.superClass.apply(this, arguments);
}
// определение наследования
ClassSub.inheritsFrom(Class); // sic!

// описание свойств и методов подкласса
ClassSub.prototype.method = function(){
ClassSub.superClass.prototype.method.apply(this, arguments);
}

Все публикации по теме ООП в JavaScript

Комментарии (26) на “ООП в Java Script (4): Наследование классов”

  1. Zeroglif:

    > Если в Object.prototype он и теперь не найдет запрашиваемого метода, то вернет ошибку
    вернёт undefined.

  2. Димус:

    Я делаю:

    function Damon() {
    	this.method_1 = function() {
    		alert("method 1");
    	}
    }
    
    function Extend() {
    	Damon.call(this);
    	this.method_1(); // получим алерт метода 1
    	this.method_2 = function() {
    		alert("method 2");
    	}
    }
    
    var test = new Extend();
    test.method_1(); // получим алерт метода 1
    test.method_2(); // получим алерт метода 2
    

    Работает, но насколько это правильно?>

  3. Азат Разетдинов:

    http://dean.edwards.name/weblog/2006/03/base/

  4. Randoom:

    >// .method объекта objSub вытаскивается из .method объекта subClass.prototype
    >alert(objSub.method == subClass.prototype.method); // true
    И где эти объекты ??? может все же :
    // .method объекта objSub вытаскивается из .method объекта ClassSub.prototype
    alert(objSub.method == ClassSub.prototype.method); // true

  5. Михайлов Денис:

    >Более того, если попытаться поменять методы класса после создания объектов подкласса, то эти изменения никак не отразятся на объектах подкласса!

    Никто и никогда не должен менять методы классов (базовых или наследуемых) после создания объектов, это принципиально не верно. Не надо этого делать!!!

  6. Михайлов Денис:

    Очень интересно, надо опробовать.
    Спасибо.

  7. karaboz:

    Randoom, спасибо, поправил (=

  8. Михайлов Денис:

    К сожалению эта концепции наследования перестает работать при 3-ем и последующих уровнях наследования. :(

  9. tt4:

    alert('one more cat was burn');

    Замените, пожалуйста, на такой вариант:

    alert('one more cat was born');

    Люблю кошек.. зачем же их жечь? :)

  10. игорь:

    Спасибо за статью.
    Проверьте орфографию :)

  11. karaboz:

    2 Михайлов Денис:
    Вы говорите неправду (=
    Я создавал три уровня наследования без проблем.
    Откуда у Вас такие мрачные мысли? (=

  12. karaboz:

    2 tt4:
    хаха! спасибо, что приостановили массовое уничтожение животных (=

  13. karaboz:

    2 Димус:
    Чтобы убедиться, что вы делаете неправильно, попробуйте добавить в класс Damon открытый метод .method_3

    Damon.prototype.method_3 = function(){
    	alert("method 3");
    }

    а затем вызывать его из объекта "подкласса" Extend:
    test.method_3(); // выведет ошибку (несуществующий метод)

    Т.е. вы не производите настоящего наследования. Что на самом деле вы делаете - так это просто копируете привилегированный метод .method_1 в новый объект. (не наследуете его, а именно копируете)

    На самом деле, для полноценного наследования должен быть создан неявно объект родительского класса. Вызывая же функцию Damon.call(this), вы не создаете такого объекта (объект может быть создан ТОЛЬКО с помощью ключевого слова new).

  14. Dmitry A. Soshnikov:

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

    this.SuperClass.apply(this, arguments);

    Конструктор третьего уровня вызовит парент (второй уровень) с правильным значением this. Но на втором уровне в конструкторе стоит та же конструкция - this.SuperClass.apply(this, arguments); а this все еще ссылается на третий уровень. Получится бесконечная рекурсия.

    P.S.: в целом - интересная статья (вернее, все 5 частей =)), спасибо.

    P.S.S.: однако ж, что делать с третьим (и ниже) уровнем наследования, коль скоро this - всегда "третий" (только что проверил - действительно, баг)?

  15. Dmitry A. Soshnikov:

    Вот, вдагонку, полностью (НЕ)работающий код:

    // Универсальная функция наследования
    Function.prototype.inheritsFrom = function(superClass) {
    	var Inheritance = function(){};
    	Inheritance.prototype = superClass.prototype;
    	this.prototype = new Inheritance();
    	this.prototype.constructor = this;
    	this.prototype.superClass = superClass;
    }
    
    // функция-конструктор Class
    var Class = function(data) {
    	this.data = data || {};
    	alert('Class');
    }
    
    // функция-конструктор ClassSub
    var ClassSub = function() {
    	this.superClass.apply(this, arguments);
    	alert('ClassSub');
    }
    // определение наследования
    ClassSub.inheritsFrom(Class); // sic!
    
    // функция-конструктор ClassSubSub
    var ClassSubSub = function() {
    	this.superClass.apply(this, arguments);
    	alert('ClassSubSub');
    }
    
    ClassSubSub.inheritsFrom(ClassSub); // sic!
    
    var c = new ClassSubSub({a: 1, b: 3});
    
    
    
    		
  16. Dmitry A. Soshnikov:

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

  17. karaboz:

    О боже! какую чудовищную ошибку я совершил! =(( Видимо я так увлекся идеей, что "если JS не находит метода в самом объекте, то он ищет его в прототипе функции-конструктора этого объекта", что допустил идиотский ляп в самом важном месте (=

    Я хотел хранить ссылку на .superClass в .prototype.superClass функции-конструктора подкласса:

    this.prototype.superClass = superClass;

    Потом, пользуясь свойством прототипов, я хотел ловко подцеплять эту ссылку при конструировании объекта подкласса, во время вызовов new ClassSub():

    this.SuperClass.apply(this, arguments);

    Но ведь это же очевидно, что когда мы начинаем вызывать подкласс самого подкласса: new ClassSubSub(), то при входе в функцию-конструктор подкласса (ClassSub), слово this ссылается не на этот подкласс, а на ClassSubSub (т.к. мы применяем функцию apply)! И получается бесконечный вызов ClassSubSub самого себя! Черт.

    Вот как надо делать по-честному:

    // Универсальная функция наследования
    Function.prototype.inheritsFrom = function(superClass) {
    	var Inheritance = function(){};
    	Inheritance.prototype = superClass.prototype;
    
    	this.prototype = new Inheritance();
    	this.prototype.constructor = this;
    	this.prototype.superClass = superClass;
    	this.superClass = superClass;
    }
    
    // функция-конструктор класса
    var Class = function(){}
    
    // описание свойств и методов класса
    Class.prototype.method = function(){};
    
    // функция-конструктор подкласса
    var ClassSub = function(){
    	this.superClass.apply(this, arguments);
    	ClassSub.superClass.apply(this, arguments);
    }
    // определение наследования
    ClassSub.inheritsFrom(Class); // sic!
    
    // описание свойств и методов подкласса
    ClassSub.prototype.method = function(){
    	this.superClass.prototype.method.apply(this, arguments);
    	ClassSub.superClass.prototype.method.apply(this, arguments);
    }
    

    Dmitry A. Soshnikov! Большое вам спасибо, что указали мне на эту досадную ошибку! Теперь наследовать можно до бесконечности (= (Михайлов Денис, приношу вам свои извинения)

    p.s. в статье я испраил весь код в сотвествие с вышеизложенным рассуждением

  18. Dmitry A. Soshnikov:

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

    function Class(params) {
    
      var Class = function oopClass() {
        // вот здесь вызовятся рекурсивно все конструкторы в нужном порядке
        if (this.__construct) {
          var t = this; var a = arguments; var __construrct;
          (__construrct = function(class) {
            if (class) {
              __construrct(class.__parent);
              class.__constructor.apply(t, a);
            }
          })(this);
        }
      }
    
       // здесь ниже определение наследования, если нужно,
       // запись в Class.prototype.__constructor = params.__constructor,
       // Class.prototype.__destructor = params.__destructor,
       // Class.prototype.__parent = params.__extends (если надо),
       // и т.д.
    
      return Class;
    
    }
    
    // создание "класса" Widget
    
    var Widget = Class({
      __constructor: function(obj) {
        if (obj) {
          for (var k in obj) {
            this[k] = obj[k];
          }
        }
        !this.data && (this.data = {});
        //alert('Widget constructor');
      },
      __destructor: function() {
        alert('Widget destructor');
      }
    });
    
    // какие-то методы Widget'a
    
    Widget.prototype.setValue = function(value) {
      this.data.value = value;
    }
    
    Widget.prototype.getValue = function() {
      alert(this.data.value);
    }
    
    Widget.prototype.getParentObj = function() {
      if (!this.__parent) {
        return null;
      }
      return this.__parent;
    }
    
    // создание "класса" WidgetRoot, наследуемого от Widget
    
    var WidgetRoot = Class({
      __extends: Widget,
      __constructor: function(_obj) {
        //alert('WidgetRoot constructor');
      },
      __destructor: function() {
        alert('WidgetRoot destructor');
      }
    });
    
    // переопределение метода родительского "класса"
    
    WidgetRoot.prototype.getValue = function() {
      alert(this.data.value + ' from WidgetRoot');
    }
    
    // а здесь уже объект "класса" WidgetRoot
    
    var wr = new WidgetRoot({a: 2, b: 3});
    wr.setValue(10);
    wr.getValue(); // свой (переопределенный) метод
    wr.__parent.getValue.call(wt); // вызов родительского
    
  19. black:

    Видим, что подкласс унаследовал метод .method своего надкласса (выполняет его, как свой собственный). Как это происходит? Сначала интерпретатор ищет метод .method в самом объекте objSub и естественно не находит его там.
    —begin emphatic
    Далее, интерпретатор обращается к ClassSub.prototype и ищет .method среди свойств этого объекта. Опять же — ничего не находит: мы нигде не задавали ничего похожего на ClassSub.prototype.method = function(){}.
    —end emphatic
    Но ведь сам объект ClassSub.prototype создан из функции-конструтора Class().
    — begin emphatic
    Поэтому, не найдя нужных свойств в самом ClassSub.prototype,
    — end emphatic
    интерпретатор обращается к .prototype функции-конструтора этого объекта. И уже здесь находит запрашиваемый метод: Class.prototype.method = function(){}.

    Мне режет слух данная формулировка поскольку из нее предполагается, что после того как вы выполнили присвоение
    Cat.prototype = new Animal(); // наследуем от класса Animal
    у объекта Cat.prottype могли бы сохраниться ранее объявленные методы или свойства

    Cat.prototype.boo = function () {alert ('boo');}
    Cat.prototype = new Animal(); // наследуем от класса Animal
    …..
    cat_thing.boo ();// как и ожидалось не работает

    – может это как-то переформулировать ?

  20. Pavel Volodko:

    Объёмный труд :-) Почитал с интересом и обнаружил много общего со своими идеями.
    Если интересно - вот, решил тоже написал статью на эту тему: Классическое наследование в JavaScript. Не так детально, конечно, но надеюсь более менее понятно.

  21. Федор:

    >> Pavel Volodko: […] вот, решил тоже написал […]

    Дык "решил" или "написал"?
    Дай-ка и я напишу…

  22. Pavel Volodko:

    To Фёдор:
    Таки "решил" и, стало быть, "написал".
    Звиняйте за опечатку.

  23. feedbee:

    Одновременно проверим, что методы надкласса >>отсались>лирическре>посиупим

  24. утко:

    Спасибо за статью, очень подробная.
    Хотя после столь полного разъяснения, приведенные модифицирования сможет реализовать каждый, но возможно кому то пригодится.

    Как не терять прототип объявленный у дочернего класса до наследования:
    [code]
    Function.prototype.inheritsFrom = function(superClass) {
    var protot = this.prototype;
    var Inheritance = function(){};
    Inheritance.prototype = superClass.prototype;

    this.prototype = new Inheritance();
    this.prototype.constructor = this;
    this.superClass = superClass;

    for (var key in protot) this.prototype[key] = protot[key];
    }

    class1 = function () {}
    class1.prototype = {
    m : 0
    }

    class2 = function () {}
    class2.prototype = {
    m1 : 1
    }

    class2.inheritsFrom(class1);

    alert(new class2().m1)

    [/code]

  25. Иван Шемякин:

    В javascript наследование немного отличается от стандартного ООП, да оно основано на прототипах. Если кратко то так:
    есть функция-конструктор Person
    function Person (name_p,family_p) {
    this.name=name_p; // свойство name
    this.family=family_p; // свойство family
    }
    создаем объект с помощью Person
    var p1=new Person("Vladik","Ivanov")
    теперь создадим объект наследник от p1, для этого создадим новую функцию конструктор Person_debt
    function Person_debt (date_debt, amount_debt) {
    this.date=date_debt; // свойство "дата взятия долга"
    this.amount=amount_debt; // свойство "сумма долга"
    }
    САМОЕ ВАЖНОЕ, укажем что прототип для данной функции-конструктора будет p1, т.е. все объекты от Person_debt будут наследниками p1
    Person_debt.prototype=p1;
    И создаем два объекта наследника
    var p_debt=new Person_debt("01.01.2013","30 000rub");
    var p_debt2=new Person_debt("01.01.2013","30 000rub");
    Они унаследует свойства родителя p1.

    Понятно разъяснено здесь по поповоду наследования http://s-engineer.ru/category/struktura-i-sintaksis-javascript/

  26. Sarhan:

    Спасибо тебе большое!

Оставить комментарий

Вам нужно войти, чтобы оставить комментарий.