, чтобы передать ему новый объект и его значение). После этого мы можем предположить, что все поля, которые должны быть в старом объекте, добавлены. Мы наследуем прототип конструктора от старого так, что экземпляры этого типа будут иметь доступ к свойствам старого прототипа. И наконец, мы можем переопределить некоторые свойства, добавляя их к новому прототипу.
Если мы чуть отредактируем функцию >dataTable
, чтоб она использовала для числовых ячеек >RTextCells
, мы получим нужную нам таблицу.
>function dataTable(data) {
> var keys = Object.keys(data[0]);
> var headers = keys.map(function(name) {
> return new UnderlinedCell(new TextCell(name));
> });
> var body = data.map(function(row) {
> return keys.map(function(name) {
> var value = row[name];
> // Тут поменяли:
> if (typeof value == "number")
> return new RTextCell(String(value));
> else
> return new TextCell(String(value));
> });
> });
> return [headers].concat(body);
>}
>console.log(drawTable(dataTable(MOUNTAINS)));
>// → … красиво отформатированная таблица
Наследование – основная часть объектно-ориентированной традиции, вместе с инкапсуляцией и полиморфизмом. Но, в то время как последние две воспринимают как отличные идеи, первая вызывает споры.
В основном потому, что её обычно путают с полиморфизмом, представляют более мощным инструментом, чем она на самом деле является, и используют не по назначению. Тогда как инкапсуляция и полиморфизм используются для разделения частей кода и уменьшения связанности программы, наследование связывает типы вместе и создаёт большую связанность.
Мы можем использовать полиморфизм без наследования. Я не советую вам полностью избегать наследования – я его использую регулярно в своих программах. Но относитесь к нему как к более хитрому трюку, который позволяет определять новые типы с минимумом кода – а не как к основному принципу организации кода. Предпочтительно расширять типы при помощи композиции – как >UnderlinedCell
построен на использовании другого объекта ячейки. Он просто хранит его в свойстве и перенаправляет вызовы из своих в его методы.
Иногда удобно знать, произошёл ли объект от конкретного конструктора. Для этого JavaScript даёт нам бинарный оператор >instanceof
.
>console.log(new RTextCell("A") instanceof RTextCell);
>// → true
>console.log(new RTextCell("A") instanceof TextCell);
>// → true
>console.log(new TextCell("A") instanceof RTextCell);
>// → false
>console.log([1] instanceof Array);
>// → true
Оператор проходит и через наследованные типы. >RTextCell
является экземпляром