Статьи

JavaScript и DOM Series: урок 1

Здравствуйте и добро пожаловать в первую часть, которая, как мы надеемся, будет обширной серией, охватывающей основные аспекты языка программирования JavaScript и DOM API.

В то время как такие инфраструктуры, как jQuery, Prototype и MooTools, являются отличными способами устранения ошибок браузера и ускорения разработки, важно знать и понимать базовые технологии. В этой серии рассказывается, что вам нужно знать о JavaScript и объектной модели документа (DOM). Даже если вы клянетесь конкретной библиотекой, это все равно принесет вам пользу — знание того, как что-то работает под кожей, может быть только хорошей вещью!

JavaScript — это динамический , свободно типизированный язык программирования на основе прототипов, который используется во многих различных средах. Помимо того, что он является преобладающим клиентским языком веб-программирования, он также используется для написания плагинов для IDE, в файлах PDF и в качестве основы для других платформ и более высоких абстракций.

JavaScript основан на стандарте ECMAScript ( ECMA-262 ) и был создан Бренданом Айчем из Netscape. Первоначально он назывался LiveScript, но позже был переименован в JavaScript, вероятно, с единственной целью вызвать путаницу.

Вот некоторые из его особенностей чуть более подробно:

  • Динамические языки программирования выполняются во время выполнения; они не компилируются. Из-за этого JavaScript иногда считается языком сценариев, а не настоящим языком программирования (очевидно, ошибочным представлением). Когда у вас есть JavaScript в HTML-документе, он будет анализироваться при загрузке страницы в браузере, следовательно, во время выполнения.
  • Свободно типизированные языки не требуют какой-либо строгой системы типизации. Если вы программировали на C или Java (не то же самое, что JavaScript), вы будете знать, что при объявлении переменной вы должны указать тип, например, ‘int’ (целое число). JavaScript отличается тем, что вам не нужно указывать тип.
  • Для выполнения наследования в JavaScript вы должны использовать нечто, называемое прототипами . JavaScript не поддерживает классы.
  • JavaScript также является функциональным языком. Он рассматривает функции как первоклассные объекты; это идея лямбда .

Понимание вышеупомянутых пунктов не важно в изучении JavaScript; Это всего лишь несколько идей, чтобы привести ваш мозг в действие, и это должно помочь вам отличить JavaScript от других языков программирования, которые вы, возможно, испытали.

Объектная модель документа, обычно сокращаемая от DOM, — это API, через который JavaScript взаимодействует с контентом на веб-сайте. JavaScript и DOM обычно рассматриваются как единое целое, поскольку для этой цели чаще всего используется JavaScript (взаимодействие с контентом в Интернете). DOM API используется для доступа, просмотра и манипулирования документами HTML и XML.

Типичная структура иерархии DOM
Базовая схема типичной иерархии DOM (упрощенная версия)

Вот несколько примечательных вещей о DOM:

  • Объект окна служит глобальным объектом, доступ к нему можно получить, просто набрав «окно». Именно внутри этого объекта выполняется весь ваш код JavaScript. Как и у всех объектов, у него есть свойства и методы.
    • Свойство — это переменная, хранящаяся под объектом. Все переменные, созданные на веб-странице, автоматически становятся свойствами объекта окна.
    • Метод — это функция, хранящаяся под объектом. Поскольку все функции хранятся в (по крайней мере) объекте окна, все они могут называться «методами».
  • DOM создает иерархию, соответствующую структуре каждого веб-документа. Эта иерархия состоит из узлов. Существует несколько различных типов DOM-узлов, наиболее важными из которых являются «Элемент», «Текст» и «Документ».
    • Узел «Элемент» представляет элемент на странице. Таким образом, если у вас есть элемент абзаца (‘<p>’), тогда к нему можно получить доступ через DOM как узел.
    • Узел «Текст» представляет весь текст (внутри элементов) на странице. Поэтому, если в вашем абзаце есть немного текста, к нему можно напрямую обратиться через DOM.
    • Узел «Документ» представляет весь документ. (это корневой узел иерархии / дерева DOM).
    • Также обратите внимание, что атрибуты элемента сами являются узлами DOM.
  • Каждый механизм компоновки имеет немного отличную реализацию стандарта DOM. Например, веб-браузер Firefox , использующий механизм разметки Gecko , имеет довольно хорошую реализацию (хотя и не полностью соответствующую спецификации W3C), но Internet Explorer , который использует механизм разметки Trident , известен своей ошибкой и неполной реализацией; причина многих страданий в сообществе веб-разработчиков!

Если вы используете Firefox и у вас еще нет аддона Firebug, я рекомендую вам скачать и установить его сейчас. Это очень полезный инструмент для получения приличной картины всей структуры документа.

Если вы хотите использовать JavaScript на веб-сайте, он должен быть включен в элемент SCRIPT:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html xmlns=»http://www.w3.org/1999/xhtml» lang=»en»>
    <head>
            <meta http-equiv=»Content-Type» content=»text/html; charset=UTF-8″ />
            <title>JavaScript!</title>
    </head>
    <body>
     
        <script type=»text/javascript»>
        // <![CDATA[
        
        // ]]>
        </script>
     
    </body>
</html>

Как вы можете видеть, у нас есть элемент SCRIPT внизу нашего документа. Атрибут TYPE должен быть строго установлен на «application / javascript», но неудивительно, что он не работает в Internet Explorer, поэтому мы застряли либо с «text / javascript», либо без атрибута TYPE вообще. Если вы заботитесь о проверке, то первое предложение, вероятно, подойдет вам.

Укажите CDATA, если вы используете XHTML

Не забудьте указать свои скрипты как CDATA!

Вы также заметили, что внутри этого элемента SCRIPT у нас есть пара закомментированных строк. Они информируют браузеры, поддерживающие XHTML, о том, что содержимое элемента SCRIPT представляет собой « символьные данные » и не должно интерпретироваться как разметка XHTML. Это действительно необходимо, если вы планируете использовать символы «<» или «>» в ​​своем коде JavaScript. Очевидно, вы можете забыть обо всем этом, если вы используете простой HTML.

Любой JavaScript, который мы помещаем в этот элемент SCRIPT, будет работать при загрузке страницы. Единственное исключение — когда элемент SCRIPT имеет атрибут ‘defer’. По умолчанию, когда браузер встречает элемент SCRIPT, он останавливает и запускает код, а затем продолжает анализ документа. Атрибут DEFER сообщает браузеру, что код не содержит кода, изменяющего документ, и поэтому может быть запущен позже. Единственная проблема в том, что он работает только в IE, поэтому, вероятно, лучше избегать этого атрибута.

Если вы хотите создать ссылку на внешний файл сценария, просто добавьте атрибут SRC к элементу SCRIPT, соответствующий его расположению. Обычно лучше иметь отдельные файлы сценариев, чем писать встроенный код, поскольку это означает, что браузер может кэшировать файл. Кроме того, вам не нужно беспокоиться о чепухе с CDATA:

1
<script type=»text/javascript» src=»my-script.js»></script>

Прежде чем мы продолжим работу с DOM, неплохо бы иметь базовые знания о некоторых основах JavaScript. Если у вас возникли проблемы с пониманием некоторых из них, не беспокойтесь — в конце концов вы их подберете!

В JavaScript вы можете иметь разные типы значений. Существуют числа, строки, логические значения, объекты, неопределенные и нулевые:

Однострочные комментарии пишутся с использованием двух косых черт (//), весь оставшийся текст в этой строке считается комментарием синтаксического анализатора. Многострочные комментарии обозначаются с помощью «/ *» и «* /» для завершения комментария.

В JavaScript все числа представлены в виде значений с плавающей точкой. При определении числовой переменной не забывайте заключать ее в кавычки.

1
2
3
4
// Note: ALWAYS use ‘var’ to declare a variable:
var leftSide = 100;
var topSide = 50;
var areaOfRectangle = leftSide * topSide;

Любая заданная вами строка воспринимается буквально, JavaScript не будет ее обрабатывать. Строка представляет собой последовательность символов Unicode и должна быть заключена в соответствующую пару одинарных или двойных кавычек.

1
2
3
4
5
var firstPart = ‘Hello’;
var secondPart = ‘World!’;
var allOfIt = firstPart + ‘ ‘ + secondPart;
// The + sign is used as the string-concatenation operator
// (it’s also used for numerical addition)

Булевы типы полезны, когда вы хотите оценить условие — посмотреть, соответствует ли оно заданным критериям. Есть только два возможных логических значения: true и false. Любое сравнение, используя логические операторы, приведет к логическому.

1
2
3
4
5
6
7
5 === (3 + 2);
// You can assign Boolean values to variables:
var veryTired = true;
// You can test for it like this:
if (veryTired) {
    // Sleep
}

‘===’, который вы видите выше, является оператором сравнения, мы рассмотрим их позже.

Функция — это специализированный объект:

1
// Using the function operator to create a new function: function myFunctionName(arg1, arg2) { // Function code goes here.

Массив также является специализированным объектом и может содержать любое количество значений данных. Для доступа к значениям данных в массиве вы должны использовать число, называемое «индексом» элемента, который вы пытаетесь получить:

01
02
03
04
05
06
07
08
09
10
11
// 2 different ways of declaring a new array,
     
// Literal:
var fruit = [‘apple’, ‘lemon’, ‘banana’];
     
// Using the Array constructor:
var fruit = new Array(‘apple’, ‘lemon’, ‘banana’);
     
fruit[0];
fruit[1];
fruit[2];

Объект — это коллекция именованных значений (пар ключ-значение). Это похоже на массив, с той лишь разницей, что вы можете указать имя для каждого значения данных.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
// 2 different ways of declaring a new Object,
     
// Literal (curly braces):
var profile = {
    name: ‘Bob’,
    age: 99,
    job: ‘Freelance Hitman’
};
     
// Using the Object constructor:
var profile = new Object();
profile.name = ‘Bob’;
profile.age = 99;
profile.job = ‘Freelance Hitman’;

Одна из наиболее распространенных конструкций в JavaScript — это оператор ‘IF’ / ‘ELSE’ . Это выглядит примерно так:

1
2
3
4
5
6
7
8
9
var legalDrinkingAge = 21;
var yourAge = 29;
     
if ( yourAge >= legalDrinkingAge ) {
    // We can use ‘alert’ to notify the user:
    alert(‘You can drink.’);
} else {
    alert(‘Sorry, you cannot drink.’);
}

Вместо того, чтобы перечислять их все здесь, я предлагаю вам посетить статью MDC об операторах . Это объясняет их во многих деталях. Я настроил несколько примеров, чтобы дать вам представление о том, как некоторые операторы используются ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
// additioa/substraction/multiply/divide
var someMaths = 2 + 3 + 4 — 10 * 100 / 2;
     
// Equality
if ( 2 == (5 — 3 ) { /* Do stuff */ } // == checks for eqaulity
     
// Inequality
if ( 2 != (5 — 3 ) { /* Do stuff */ }
     
// Strict Equality operators:
// (I suggest using these)
2 === 2 // Instead of 2 == 2
2 !== 3 // Instead of 2 != 3
     
// Assignment:
var numberOfFruit = 9;
numberOfFruit -= 2;
numberOfFruit += 2;

Циклы полезны, когда вам нужно просмотреть все элементы в массиве или все элементы объекта. Наиболее распространенный способ выполнения цикла в JavaScript — использование оператора FOR или WHILE.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
var envatoTutSites = [‘NETTUTS’,’PSDTUTS’,’AUDIOTUTS’,’AETUTS’,’VECTORTUTS’];
     
// WHILE loop
var counter = 0;
var lengthOfArray = envatoTutSites.length;
while (counter < lengthOfArray) {
    alert(envatoTutSites[counter]);
    counter++;
}
     
// FOR loop
// (The i stands for «iterator» — you could name it anything)
for (var i = 0, length = envatoTutSites.length; i < length; i++) {
    alert(envatoTutSites[i]);
}
О цикле FOR в JavaScript

Циклы FOR более популярны для циклического перемещения по массивам.

Давайте предположим, что у нас есть базовый документ XHTML, содержащий абзац и неупорядоченный список:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!DOCTYPE html PUBLIC «-//W3C//DTD XHTML 1.0 Strict//EN» «http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd»>
<html xmlns=»http://www.w3.org/1999/xhtml» lang=»en»>
    <head>
            <meta http-equiv=»Content-Type» content=»text/html; charset=UTF-8″ />
            <title>JavaScript!</title>
    </head>
    <body>
      
        <p id=»intro»>My first paragraph…</p>
     
        <ul>
            <li>List item 1</li>
            <li>List item 1</li>
            <li>List item 1</li>
            <li>List item 1</li>
            <li>List item 1</li>
        </ul>
     
        <script type=»text/javascript»>
        // <![CDATA[
        
        // ]]>
        </script>
     
    </body>
</html>

В этом первом примере мы собираемся получить доступ к нашему абзацу с помощью метода DOM ‘getElementById’:

(Этот код входит в элемент SCRIPT в приведенном выше шаблоне).

1
2
3
var introParagraph = document.getElementById(‘intro’);
// We now have a reference to the DOM node.
// node represents the intro paragraph.

Переменная introParagraph теперь является ссылкой на узел DOM. С этим узлом мы можем сделать несколько вещей — мы можем запросить его содержимое и атрибуты и можем манипулировать любым его аспектом. Мы можем удалить его, клонировать или переместить в другие части дерева DOM.

Ко всему, что присутствует в документе, мы можем получить доступ с помощью JavaScript и DOM API. Таким образом, мы можем захотеть получить доступ к неупорядоченному списку аналогичным образом, единственная проблема в том, что у него нет идентификатора. Вы могли бы дать ему идентификатор и затем использовать тот же метод, что и выше, или мы могли бы получить к нему доступ, используя getElementsByTagName:

1
2
3
var allUnorderedLists = document.getElementsByTagName(‘ul’);
// ‘getElementsByTagName’ returns a live node collection/list
// — It’s very similar to an array with a few slight differences.

Метод ‘getElementsByTagName’ возвращает коллекцию / список активных узлов. Это похоже на массив в том, что он имеет свойство длины. Важно отметить, что эти коллекции являются «живыми» — если вы добавите новый элемент в DOM, то коллекция обновится сама. Поскольку это массивоподобный объект, мы можем получить доступ к каждому узлу через индекс от 0 до общей длины коллекции (минус 1):

01
02
03
04
05
06
07
08
09
10
11
// Access single unordered list: [0] index
var unorderedList = document.getElementsByTagName(‘ul’)[0];
     
// Create Node list of all list items within the UL:
var allListItems = unorderedList.getElementsByTagName(‘li’);
    
// Now, we can loop through each list item using a FOR loop:
for (var i = 0, length = allListItems.length; i < length; i++) {
    // Extract text node within and alert its content:
    alert( allListItems[i].firstChild.data );
}
Доступ к узлам и атрибутам в DOM

Доступ к узлам и атрибутам в DOM

Термин «траверс» используется для описания действия путешествия по DOM, поиска узлов. DOM API предоставляет нам множество свойств узлов, которые мы можем использовать для перемещения вверх и вниз по всем узлам в документе.

Эти свойства присущи всем узлам и позволяют вам получить доступ к связанным / закрыть узлы:

  • Node.childNodes : вы можете использовать это для доступа ко всем прямым дочерним узлам одного элемента. Это будет похожий на массив объект, который вы можете перебрать. Узлы в этом массиве будут включать все различные типы узлов, включая текстовые узлы и другие узлы элементов.
  • Node.firstChild : это то же самое, что и доступ к первому элементу в массиве ‘childNodes’ (‘Element.childNodes [0]’). Это просто ярлык.
  • Node.lastChild : это то же самое, что и доступ к последнему элементу в массиве childNodes (Element.childNodes [Element.childNodes.length-1]). Это просто ярлык.
  • Node.parentNode : это дает вам доступ к родительскому узлу вашего текущего узла. Там будет только один родительский узел. Чтобы получить доступ к бабушке и дедушке, вы просто должны использовать «Node.parentNode.parentNode» и т. Д.
  • Node.nextSibling : это дает вам доступ к следующему узлу на том же уровне в дереве DOM.
  • Node.previousSibling : это дает вам доступ к последнему узлу того же уровня в дереве DOM.
Обход DOM

Обход документа (упрощенный — пожалуйста, прочитайте ниже)

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

Одна вещь, которую следует отметить в отношении приведенного выше рисунка: элементы списка могут быть получены таким образом, только если между ними нет пробелов. Поскольку в документе могут быть текстовые узлы и узлы элементов, пространство между «<ul>» и первым «<li>» фактически считается самим узлом. Точно так же неупорядоченный список на самом деле не является следующим братом абзаца — поскольку он находится на новой строке, между двумя элементами есть пространство — следовательно, еще один узел! Обычно в этой ситуации вы должны были бы пройти через массив childNodes и протестировать nodeType. «NodeType», равный 1, означает, что это элемент, 2 означает, что это атрибут, 3 означает, что это текстовый узел. Вы можете увидеть полный список здесь: https://developer.mozilla.org/En/DOM/Node.nodeType .

Вот как все основные библиотеки JavaScript работают за кулисами; используя собственные методы и свойства DOM, чтобы дать вам доступ к этим элементам через хорошо отточенную абстракцию. Что отличает вас от приверженцев фреймворка, так это то, что у вас теперь есть представление о том, как выжить без фреймворка (если вы этого еще не сделали)!

Ну, вот и все. Я надеюсь, что вы чему-то научились из всех моих разговоров. Мы надеемся, что в следующей части серии мы сфокусируемся на некоторых более подходящих примерах мы, вероятно, рассмотрим модель событий браузера.

В то же время, если вы еще этого не сделали, посмотрите на эти выступления Дуга Крокфорда (видео-сайт Yahoo!):

Спасибо за прочтение!