1. В JS реализовано так называемое "прототипическое наследование". Каждый дочерний об-т имеет ссылку на родительский, а значит на все его свойства и методы. Таким образом, родительский об-т является прототипом для дочернего
2. В основе всех об-тов лежит встроенный JS об-т Object. Для об-тов это object Object, для массивов object Array, для функций object Function и т.д. (см документ objects-and-types.html). Т.е. корневой встроенный об-т является прототипом для всех дочерних. Соответственно, все дочерние будут наследовать его свойства и методы
Листинг 1. Определение прототипа массива
Вывод в консоль Листинга 1 покажет нам, что у любого массива есть 2 св-ва length - длина массива и [[Prototype]] - содержит ссылку на встроенный об-т Array(), который в свою очередь содержит кучу стандартных методов массива (find, filter и т.д.)
Рис. 1 Прототип всех массивов object Array и его методы
Как видим, обычный массив JS имеет своим прототипом объект, который содержит такие методы, как concat, filter, find и много других. То есть стандартные методы любого массива
Рис. 2 Схема прототипического наследования на примере массивов
Рис. 3 Прототипом всех типов данных в JS является один корневой об-т
1. Наследование об-тов в JS осуществляется через Object.create
Листинг 2. Наследование простых об-тов
Рис. 4 Стандартное наследование об-тов
2. Интроспекция (установка связи между об-тами) или Определение прототипа об-та. В примере выше об-т b является дочерним для об-та a, а значит говорится, что об-т а является прототипом для об-та b. Программно это определяется через метод Object.getPrototypeOf, а проверка, какой об-т является прототипом проверяемого через isPrototypeOf
Листинг 3. Получение прототипа об-та через Object.getPrototypeOf
Листинг 4. В родительской цепочке getPrototypeOf всегда указывает на корневой родительский об-т
Листинг 5. Проверка прототипа об-та с помощью isPrototypeOf
3. Проверка св-в и методов. Проверка на предмет того, являются ли св-ва об-та его собственными или унаследованными от родительских об-тов осуществляется с помощью метода hasOwnProperty
Листинг 6. Проверка родных и унаследованных св-в об-та
1. Пример приведённый в Листинге 2, хотя и имеет смысл, редко применяется на практике. В реальной практике для более универсальной работы с об-тами и их наследованием применяются классы, которые рассмотрены в соответствующем разделе. До появления классов эту роль выполняла ф-ция - конструктор. Т.е., стандартная ф-ция, которая вызывается с помощью ключевого слова new.
Все примеры идущие ниже основаны на использовании ф-ции - конструктора, которая является полным заменителем классов. Поэтому в отношении неё и создаваемых ею об-тов будем пользоваться, как термином "ф-ция-конструктор", так и терминами "класс" и "экземпляр класса"
Листинг 7. Простое наследование с использованием ф-ции конструктора без параметров
Листинг 3 показывает, что в рамках области видимости ф-ции Student, мы вызываем ф-цию User, но крепим к ней this ф-ции Student
Рис. 5 Стандартное наследование с помощью ф-ции конструктора
Чтобы Листинг 3 был более понятен, покажем пример с наследованием свойств. У класса User есть св-ва name (имя пользователя) и age (возраст). Мы хотим, чтобы производный от него класс Student их наследовал и имел кроме того своё св-во faculty (факультет)
Листинг 8. Наследование класса вместе со св-вами
Добавим ещё один дочерний класс Teacher (преподаватель). И новые св-ва для него faculty (факультет) и salary (зарплата)
Листинг 9. Добавляем ещё один дочерний класс Teacher
Таким образом, цепочка наследования будет следующая (рис. 6)
Рис. 6 Один об-т может быть родительским для многих дочерних
2. Наследование методов.
Простое наследование метдов
Листинг 10. Класс Student вместе со св-вами name и age унаследует и метод getData()
Методы, как и св-ва можно перезаписать
Листинг 11. Перезаписывание ("затенение") метода (также можно перезаписать и св-ва)
У вышеприведённого способа наследования методов есть недостаток, а именно: при инициализации об-та дочернего класса родительский метод копируется в дочерний класс, в то время, как в JS есть возможность передать метод по ссылке. Т.о., метод будет создан один раз в родительском классе, а в дочерних классах он будет просто ссылаться на родительский. Для этого в ф-циях - конструкторах существует св-во prototype
Листинг 12. Более правильный способ создания методов, это использовать встроенный в ф-цию - конструктор св-во prototype
Листинг 13. Необходимо скорректировать, чтобы Student.prototype.constructor был равен Student, а не User
3. Интроспекция (установка связи между об-тами) в ф-ции - конструкторе. Для определения прототипа об-та (то есть, содержится ли такой об-т в родительской цепочке для данного экземпляра) используется оператор instanceof
Листинг 14. Использование оператора instanceof для определения прототипов экземпляра класса
Создать обычный об-т Figure (фигура). Создать от него два дочерних об-та Rectangle (четырёхугольник) и Circle (окружность). Figure должен содержать поле square (площадь) и метод getSquare, который должен его возвращать. Дочерние об-ты должны иметь метод setSquare, который принимает об-т параметров (для четырёхугольника - 2 стороны: a, b И для окружности - радиус: r) и возвращать вычисленный результат. При получении параметров, приводить их к числовому типу (Number), затем делать проверку (isNaN) - если проверка не пройдена, выводить сообщение в консоль и завершать выполнение программы выбросом ошибки (throw new Error())
Проверка работы программы - вызов метода setSquare с соответствующими параметрами и getSquare для получения результата
Площадь четырёхугольника: S = a * b
Площадь окружности: S = π * r^2