Выразительный JavaScript (Хавербеке) - страница 67

, чтобы передать ему новый объект и его значение). После этого мы можем предположить, что все поля, которые должны быть в старом объекте, добавлены. Мы наследуем прототип конструктора от старого так, что экземпляры этого типа будут иметь доступ к свойствам старого прототипа. И наконец, мы можем переопределить некоторые свойства, добавляя их к новому прототипу.

Если мы чуть отредактируем функцию >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 построен на использовании другого объекта ячейки. Он просто хранит его в свойстве и перенаправляет вызовы из своих в его методы.

Оператор instanceof

Иногда удобно знать, произошёл ли объект от конкретного конструктора. Для этого 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 является экземпляром