Марейн Хавербеке - Выразительный JavaScript
- Название:Выразительный JavaScript
- Автор:
- Жанр:
- Издательство:неизвестно
- Год:неизвестен
- ISBN:978-1593275846
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Марейн Хавербеке - Выразительный JavaScript краткое содержание
В процессе чтения вы познакомитесь с основами программирования и, в частности, языка JavaScript, а также выполните несколько небольших проектов. Один из самых интересных проектов — создание своего языка программирования.
Выразительный JavaScript - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
То есть, вот ещё один способ графически представить дерево документа:

Листья – текстовые узлы, а стрелки показывают взаимоотношения отец-ребёнок между узлами.
Стандарт
Использовать загадочные цифры для представления типа узла – это подход не в стиле JavaScript. Позже мы встретимся с другими частями интерфейса DOM, которые тоже кажутся чуждыми и нескладными. Причина в том, что DOM разрабатывался не только для JavaScript. Он пытается определить интерфейс, не зависящий от языка, который можно использовать и в других системах – не только в HTML, но и в XML, который представляет из себя формат данных общего назначения с синтаксисом, напоминающим HTML.
Получается неудобно. Хотя стандарты – и весьма полезная штука, в нашем случае преимущество независимости от языка не такое уж и полезное. Лучше иметь интерфейс, хорошо приспособленный к языку, который вы используете, чем интерфейс, который будет знаком при использовании разных языков.
Чтобы показать неудобную интеграцию с языком, рассмотрим свойство childNodes
, которое есть у узлов DOM. В нём содержится объект, похожий на массив, со свойством length
, и пронумерованные свойства для доступа к дочерним узлам. Но это – экземпляр типа NodeList
, не настоящий массив, поэтому у него нет методов вроде forEach
.
Есть также проблемы, связанные с плохой продуманностью системы. К примеру, нельзя создать новый узел и сразу добавить к нему свойства или дочерние узлы. Сначала нужно его создать, затем добавить дочерние по одному, и в конце назначить свойства по одному, с использованием побочных эффектов. Код, плотно работающий с DOM, получается длинным, некрасивым и со множеством повторов.
Но эти проблемы не фатальные. JavaScript позволяет создавать абстракции. Легко написать вспомогательные функции, позволяющие выражать операции более понятно и коротко. Вообще, такого рода инструменты предоставляют много библиотек, направленных на программирование для браузера.
Обход дерева
Узлы DOM содержат много ссылок на соседние. Это показано на диаграмме:

Хотя тут показано только по одной ссылке каждого типа, у каждого узла есть свойство parentNode
, указывающего на его родительский узел. Также у каждого узла-элемента (тип 1) есть свойство childNodes
, указывающее на массивоподобный объект, содержащий его дочерние узлы.
В теории можно пройти в любую часть дерева, используя только эти ссылки. Но JavaScript предоставляет нам много дополнительных вспомогательных ссылок. Свойства firstChild
и lastChild
показывают на первый и последний дочерний элементы, или содержат null
у тех узлов, у которых нет дочерних. previousSibling
и nextSibling
указывают на соседние узлы – узлы того же родителя, что и текущего узла, но находящиеся в списке сразу до или после текущей. У первого узла свойство previousSibling
будет null
, а у последнего nextSibling
будет null
.
При работе с такими вложенными структурами пригождаются рекурсивные функции. Следующая ищет в документе текстовые узлы, содержащие заданную строку, и возвращает true
, когда находит:
function talksAbout(node, string) {
if (node.nodeType == document.ELEMENT_NODE) {
for (var i = 0; i < node.childNodes.length; i++) {
if (talksAbout(node.childNodes[i], string))
return true;
}
return false;
} else if (node.nodeType == document.TEXT_NODE) {
return node.nodeValue.indexOf(string) > -1;
}
}
console.log(talksAbout(document.body, "книг"));
// → true
Свойства текстового узла nodeValue
содержит строчку текста.
Поиск элементов
Часто бывает полезным ориентироваться по этим ссылкам между родителями, детьми и родственными узлами и проходить по всему документу. Однако если нам нужен конкретный узел в документе, очень неудобно идти по нему, начиная с document.body
и тупо перебирая жёстко заданный в коде путь. Поступая так, мы вносим в программу допущения о точной структуре документа – а её мы позже можем захотеть поменять. Другой усложняющий фактор – текстовые узлы создаются даже для пробелов между узлами. В документе из примера у тега body
не три дочерних ( h1
и два p
), а целых семь: эти три плюс пробелы до, после и между ними.
Так что если нам нужен атрибут href
из ссылки, мы не должны писать в программе что-то вроде: «второй ребёнок шестого ребёнка document.body». Лучше бы, если б мы могли сказать: «первая ссылка в документе». И так можно сделать:
var link = document.body.getElementsByTagName("a")[0];
console.log(link.href);
У всех узлов-элементов есть метод getElementsByTagName
, собирающий все элементы с данным тегом, которые происходят (прямые или не прямые потомки) от этого узла, и возвращает его в виде массивоподобного объекта.
Чтобы найти конкретный узел, можно задать ему атрибут id
и использовать метод document.getElementById
.
Мой страус Гертруда:
var ostrich = document.getElementById("gertrude");
console.log(ostrich.src);
Третий метод – getElementsByClassName
, который, как и getElementsByTagName
, ищет в содержимом узла-элемента и возвращает все элементы, содержащие в своём классе заданную строчку.
Меняем документ
Почти всё в структуре DOM можно менять. У узлов-элементов есть набор методов, которые используются для их изменения. Метод removeChild
удаляет заданную дочерний узел. Для добавления узла можно использовать appendChild
, который добавляет узел в конец списка, либо insertBefore
, добавляющий узел, переданную первым аргументом, перед узлом, переданным вторым аргументом.
Один
Два
Три
var paragraphs = document.body.getElementsByTagName("p");
document.body.insertBefore(paragraphs[2], paragraphs[0]);
Узел может существовать в документе только в одном месте. Поэтому вставляя параграф «Три» перед параграфом «Один» мы фактически удаляем его из конца списка и вставляем в начало, и получаем «Три/Один/Два». Все операции по вставке узла приведут к его исчезновению с текущей позиции (если у него таковая была).
Метод replaceChild
используется для замены одного дочернего узла другим. Он принимает два узла: новый, и тот, который надо заменить. Заменяемый узел должен быть дочерним узлом того элемента, чей метод мы вызываем. Как replaceChild
, так и insertBefore
в качестве первого аргумента ожидают получить новый узел.
Создание узлов
В следующем примере нам надо сделать скрипт, заменяющий все картинки (тег ) в документе текстом, содержащимся в их атрибуте alt
, который задаёт альтернативное текстовое представление картинки.
Интервал:
Закладка: