Опубликован: 19.10.2006 | Уровень: для всех | Доступ: платный
Лекция 9:

Наследование и замыкание

< Лекция 8 || Лекция 9: 12 || Лекция 10 >
Аннотация: Метод наследования. Полезные (и опасные) свойства замыкания.

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

Наследование

В "Основы объектно-ориентированного программирования" была создана функция 'Cat':

function Cat(name){
  this.name = name;
}
Cat.prototype = {
  species:  'Cat',
  talk:     function(){ alert('Meow!'); },
  callOver: function(){ alert(this.name+' ignores you'); },
  pet:      function(){ alert('Pet!'); }
}

Теперь можно создать любое количество котов, но как быть, если мы захотим создать объект другого типа, например, собаку? В этом случае понадобится создать совершенно новую функцию, со своими собственными прототипами. Если два объекта используют одни и те же функции (например, можно было бы добавить функции sleep (спать), eat (есть), и play (играть)), то в результате мы бы имели чрезмерное дублирование кода. Решением является концепция наследования.

По сути наследование позволяет определить объекты "предки" и "потомки". Потомок наследует все свойства своего предка. Можно было создать, например, функцию Animal, Pet или Mammal. Обе функции Cat и Dog обладали бы многими свойствами функции предка Animal, и нам пришлось бы писать этот код один раз.

Проблема в том, что JavaScript не имеет в действительности встроенного механизма наследования, поэтому эту функциональность необходимо создавать самостоятельно. Для этого существует несколько различных способов. Один из них состоит в использовании функции call. Эта функция позволяет вызывать одну функцию из контекста другой, т.е. мы можем определить, как действует ключевое слово this. С помощью call можно написать класс Animal (Животное), а затем вызвать его из класса Cat или Dog.

function Animal(name){
  this.name = name;

  this.species = 'Animal';
  this.sleep   = function(){ alert(this.name+' спит: Хрррр'); }
}
function Cat(name){
  Animal.call(this, name);

  this.talk = function(){ alert('Мяу!'); }
}
function Dog(name){
  Animal.call(this, name);

  this.talk = function(){ alert('Гав!'); }
}

var sam = new Cat('Sam');
var joe = new Dog('Joe');
sam.sleep(); // Sam спит: Хрррр
joe.sleep(); // Joe спит: Хрррр

sam.talk();  // Мяу!
joe.talk();  // Гав!

Хотя это работает, мы немного ограничены в своих возможностях. Например, прототипирование не действует при использовании этого метода: все прототипы, заданные на Animal, не будут переноситься в функции Cat или Dog. Как мы знаем из "Основы объектно-ориентированного программирования" , определенные внутренне с помощью " this." функции создают новый экземпляр всякий раз при создании новой копии предка. В этом случае всякий раз при создании функции Animal, Cat или Dog появляется новая копия функций species и sleep. Как можно догадаться, это не самый эффективный способ.

Лучшим подходом является прототипирование всего родительского класса на классе-потомке. Это предоставляет доступ ко всем свойствам и методам класса предка:

function Animal(name){
  this.name = name;
}
Animal.prototype = {
  species: 'Animal',
  sleep  : function(){ alert(this.name+' спит: Хрррр'); }
}

function Cat(name){
  Animal.apply(this, arguments);
}
Cat.prototype         = new Animal;
Cat.prototype.species = 'Cat';
Cat.prototype.talk    = function(){ alert('Мяу!'); }

function Dog(name){
  Animal.apply(this, arguments);
}
Dog.prototype         = new Animal;
Dog.prototype.talk    = function(){ alert('Гав!'); }

var sam = new Cat('Sam');
var joe = new Dog('Joe');

sam.sleep(); // Sam спит : Хрррр
joe.sleep(); // Joe спит: Хрррр

alert(sam.species); // Cat
alert(joe.species); // Animal - для Dog функция species не определена

Можно продолжить это дальше и создать отдельные функции для различных пород собак или кошек и т.д.

< Лекция 8 || Лекция 9: 12 || Лекция 10 >
Елена Сапегова
Елена Сапегова

После прохождения теоретической части пришло письмо об окончании теоретической части курса, будет ли практическая часть?

Рустам Рахимов
Рустам Рахимов

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

function Complete() {

    var x = "Имя: " + document.tutform.firstname.value;

alert(x);

} - Так брать значение из формы tutform, firstname-получаем значение из имени. 

<INPUT TYPE="button" VALUE="Готово" onClick="Complete();"> - Нужно к кнопке прописать событие, при нажатие на кнопку готово, чтобы возвращалось значение с помощью функции. А так ничего не работает, и смысла учить нету, если не знать почему не работает.

 

Анатолий Федоров
Анатолий Федоров
Россия, Москва, Московский государственный университет им. М. В. Ломоносова, 1989
Олег Волков
Олег Волков
Россия, Балаково, МБОУ СОШ 19