Марейн Хавербеке - Выразительный JavaScript
- Название:Выразительный JavaScript
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:978-1593275846
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Марейн Хавербеке - Выразительный JavaScript краткое содержание
В процессе чтения вы познакомитесь с основами программирования и, в частности, языка JavaScript, а также выполните несколько небольших проектов. Один из самых интересных проектов — создание своего языка программирования.
Выразительный JavaScript - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Если мы чуть отредактируем функцию 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
является экземпляром TextCell
, поскольку RTextCell.prototype
происходит от TextCell.prototype
. Оператор также можно применять к стандартным конструкторам типа Array
. Практически все объекты – экземпляры Object
.
Итог
Получается, что объекты чуть более сложны, чем я их подавал сначала. У них есть прототипы – это другие объекты, и они ведут себя так, как будто у них есть свойство, которого на самом деле нет, если это свойство есть у прототипа. Прототипом простых объектов является Object.prototype
.
Конструкторы – функции, имена которых обычно начинаются с заглавной буквы – можно использовать с оператором new
для создания объектов. Прототипом нового объекта будет объект, содержащийся в свойстве prototype
конструктора. Это можно использовать, помещая в прототип свойства, общие для всех экземпляров данного типа. Оператор instanceof
, если ему дать объект и конструктор, может сказать, является ли объект экземпляром этого конструктора.
Для объектов можно сделать интерфейс и сказать всем, чтобы они общались с объектом только через этот интерфейс. Остальные детали реализации объекта теперь инкапсулированы, скрыты за интерфейсом.
А после этого никто не запрещал использовать разные объекты при помощи одинаковых интерфейсов. Если разные объекты имеют одинаковые интерфейсы, то и код, работающий с ними, может работать с разными объектами одинаково. Это называется полиморфизмом, и это очень полезная штука.
Определяя несколько типов, различающихся только в мелких деталях, бывает удобно просто наследовать прототип нового типа от прототипа старого типа, чтобы новый конструктор вызывал старый. Это даёт вам тип объекта, сходный со старым, но при этом к нему можно добавлять свойства или переопределять старые.
Упражнения
Векторный тип
Напишите конструктор Vector
, представляющий вектор в двумерном пространстве. Он принимает параметры x
и y
(числа), которые хранятся в одноимённых свойствах.
Дайте прототипу Vector
два метода, plus
и minus
, которые принимают другой вектор в качестве параметра и возвращают новый вектор, который хранит в x
и y
сумму или разность двух векторов (один this
, второй – аргумент).
Добавьте геттер length
в прототип, подсчитывающий длину вектора – расстояние от (0, 0) до (x, y).
// Ваш код
console.log(new Vector(1, 2).plus(new Vector(2, 3)));
// → Vector{x: 3, y: 5}
console.log(new Vector(1, 2).minus(new Vector(2, 3)));
// → Vector{x: -1, y: -1}
console.log(new Vector(3, 4).length);
// → 5
Ещё одна ячейка
Создайте тип ячейки StretchCell(inner, width, height)
, соответствующий интерфейсу ячеек таблицы из этой главы. Он должен оборачивать другую ячейку (как делает UnderlinedCell
), и убеждаться, что результирующая ячейка имеет как минимум заданные ширину и высоту, даже если внутренняя ячейка – меньше.
// Ваш код.
var sc = new StretchCell(new TextCell("abc"), 1, 2);
console.log(sc.minWidth());
// → 3
console.log(sc.minHeight());
// → 2
console.log(sc.draw(3, 2));
// → ["abc", " "]
Интерфейс к последовательностям
Разработайте интерфейс, абстрагирующий проход по набору значений. Объект с таким интерфейсом представляет собой последовательность, а интерфейс должен давать возможность в коде проходить по последовательности, работать со значениями, которые её составляют, и как-то сигнализировать о том, что мы достигли конца последовательности.
Задав интерфейс, попробуйте сделать функцию logFive
, которая принимает объект-последовательность и вызывает console.log
для первых её пяти элементов – или для меньшего количества, если их меньше пяти.
Затем создайте тип объекта ArraySeq
, оборачивающий массив, и позволяющий проход по массиву с использованием разработанного вами интерфейса. Создайте другой тип объекта, RangeSeq
, который проходит по диапазону чисел (его конструктор должен принимать аргументы from
и to
).
// Ваш код.
logFive(new ArraySeq([1, 2]));
// → 1
// → 2
logFive(new RangeSeq(100, 1000));
// → 100
// → 101
// → 102
// → 103
// → 104
7. Проект: электронная жизнь
Вопрос о том, могут ли машины думать, так же уместен, как вопрос о том, могут ли подводные лодки плавать.
Эдсгер Дейкстра, «Угрозы вычислительной науке»В главах-проектах я перестану закидывать вас теорией, и буду работать вместе с вами над программами. Теория незаменима при обучении программированию, но она должна сопровождаться чтением и пониманием нетривиальных программ.
Читать дальшеИнтервал:
Закладка: