|
@@ -0,0 +1,186 @@
|
|
|
+## Введение в **DOM**.
|
|
|
+
|
|
|
+**DOM** (*Document Object Model*) - внутренние объекты и функции *браузерного* **JS**, которые позволяют работать с деревом тэгов текущей загруженной страницы. **JS** через это **API** имеет полный доступ ко
|
|
|
+всему тому, что есть в HTML и CSS.
|
|
|
+
|
|
|
+### Корень
|
|
|
+
|
|
|
+Корнем дерева элементов **DOM** является объект `document`
|
|
|
+
|
|
|
+## #Поиск элементов
|
|
|
+
|
|
|
+Что бы найти элемент, нужно обратится к методу `document`, или любого другого элемента, в который нужно что-то найти:
|
|
|
+
|
|
|
+```javascript
|
|
|
+var el = document.getElementById("someId"); //обратите внимания, без #
|
|
|
+var el2 = document.querySelector("#someId"); //поиск по любому селектору, аналог jQuery
|
|
|
+var el3 = document.querySelectorAll("a"); //поиск всех тэгов a
|
|
|
+```
|
|
|
+
|
|
|
+### Создание элементов **DOM**
|
|
|
+
|
|
|
+```javascript
|
|
|
+document.createElement("a"); //обратите внимание, без <>
|
|
|
+```
|
|
|
+
|
|
|
+Добавление элементов:
|
|
|
+```javascript
|
|
|
+var tr = document.createElement("tr");
|
|
|
+var td = document.createElement("td");
|
|
|
+var td2 = document.createElement("td");
|
|
|
+
|
|
|
+tr.appendChild(td); //добавление ячейки в конец строки таблицы.
|
|
|
+tr.insertBefore(tr.childNodes[0],td2); //добавление ячейки перед первой ячейкой (в самое начало строки таблицы)
|
|
|
+```
|
|
|
+
|
|
|
+Ссылка на родительский элемент находится в свойстве `parentElement`:
|
|
|
+
|
|
|
+```javascript
|
|
|
+tr.childNodes[0].parentElement == tr
|
|
|
+```
|
|
|
+
|
|
|
+
|
|
|
+### Свойства объектов или наборов объектов элементов в **DOM**
|
|
|
+
|
|
|
+- `value` - **свойство** а не функция для значения поля ввода.
|
|
|
+- `attributes` - объект `attributes` с атрибутами html-тэга. Также есть 4 функции для работы с атрибутами:
|
|
|
+ - `hasAttribute` - проверка на наличие атрибута
|
|
|
+ - `getAttribute` - чтение
|
|
|
+ - `setAttribute` - запись
|
|
|
+ - `removeAttribute` - удаление
|
|
|
+- `style` - объект стиля элемента
|
|
|
+- `innerHTML` - строка вложенного HTML в элементе.
|
|
|
+- `innerText` - строка вложенного текста в элементе.
|
|
|
+
|
|
|
+### События
|
|
|
+
|
|
|
+Каждый элемент **DOM** содержит множество свойств `on...`, в которые вы можете занести тот или иной обработчик события:
|
|
|
+
|
|
|
+```javascript
|
|
|
+document.onmousemove = function(){
|
|
|
+ document.write("mouse move <br/>");
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Так же можно добавлять обработчики используя метод элемента `addEventListener`:
|
|
|
+
|
|
|
+```javascript
|
|
|
+document.addEventListener("mousemove",function(){
|
|
|
+ document.write("mouse move <br/>");
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+### Нюансы
|
|
|
+
|
|
|
+#### Элемент в дереве
|
|
|
+может встречаться только один раз. Вы не можете вставить элемент дважды в дерево. Если вы хотите создать копию элемента в вашем DOM-дереве, используйте `cloneNode`.
|
|
|
+
|
|
|
+#### HTML/CSS
|
|
|
+Всё, что вы видели в HTML/CSS может быть установлено как свойства объекта-узла DOM и тут же будет отображено в браузере
|
|
|
+
|
|
|
+#### `children` и `childNodes`
|
|
|
+- Узлами (`Node`) может быть любой текст в HTML, в том числе обычный текст и тот или иной тэг. Дочерние элементы каждого элемента находятся в **псевдомассиве** `childNodes`
|
|
|
+- В **псевдомассиве** `children` находятся только дочерние узлы-тэги, но без обычного текста.
|
|
|
+
|
|
|
+
|
|
|
+> Задание
|
|
|
+> Сделайте любое предыдущее задание по конструированию **HTML** используя **DOM**, а не конструирование строки. Проанализируйте отличия.
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+## Замыкания, приватные методы и данные.
|
|
|
+
|
|
|
+> One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions.
|
|
|
+> -— <cite>Guy Steele on the design of Scheme</cite>
|
|
|
+
|
|
|
+> Closures are one of those few curious concepts that are paradoxically difficult because they are so simple. Once a programmer becomes used to a complex solution to a problem, simple solutions to the same problem feel incomplete and uncomfortable. But, as we will soon see, closures can be a simpler, more direct solution to the problem of how to organise data and code than objects.
|
|
|
+> -- <cite>Doug Hoyte</cite>
|
|
|
+
|
|
|
+Функция в **JS** находится сразу в двух контекстах: *динамическом* (`this`, значения параметров) и *лексическом* (переменные из более высоких областей
|
|
|
+видимости в **месте определения функции**). *Динамический контекст* - это контекст **вызова** функции - значение параметров и окружение на момент вызова;
|
|
|
+*лексический контекст* - контекст **определения** функции, её вложенности в другие области видимости, доступ к которым функция имеет и после окончания
|
|
|
+выполнения функций-владельцев этих областей видимости.
|
|
|
+
|
|
|
+### makeAdder
|
|
|
+
|
|
|
+```javascript
|
|
|
+function makeAdder(x){
|
|
|
+ function adder(y){
|
|
|
+ return x + y;
|
|
|
+ }
|
|
|
+ return adder
|
|
|
+}
|
|
|
+
|
|
|
+var add5 = makeAdder(5);
|
|
|
+var greeter = makeAdder("Hi, ");
|
|
|
+
|
|
|
+alert(add5(2));
|
|
|
+alert(greeter("John"));
|
|
|
+```
|
|
|
+
|
|
|
+В примере выше `5`,`"Hi, "`, `2` и `"John"` находятся в динамическом контексте вызова функции. А вот значение `x` в `adder` находится в *лексическом*
|
|
|
+контексте. На момент запуска функций `add5` и `greeter` функции `makeAdder` уже давно отработали, однако значение `x` и область видимости продолжают
|
|
|
+присутствовать в функциях `add5` и `greeter`. Это называется **замыканием** - данные в локальной области видимости отработавшей функции и код, который
|
|
|
+использует эти данные впоследствии. В широком смысле **замыкание** является *объектом*, так как хранит в единой сущности код и данные.
|
|
|
+
|
|
|
+В контексте **JS** *замыкания* очень удобны для огораживания кода, сохранения состояния переменных "на будущее", для функций обратного вызова. Так же
|
|
|
+*замыкания* удобны для организации приватных полей у объектов **JS**.
|
|
|
+
|
|
|
+### makeCounter
|
|
|
+
|
|
|
+```javascript
|
|
|
+
|
|
|
+function makeCounter(){
|
|
|
+ var counter = 0;
|
|
|
+
|
|
|
+ return function(){
|
|
|
+ return counter++;
|
|
|
+ }
|
|
|
+}
|
|
|
+```
|
|
|
+
|
|
|
+Функция выше создает счетчик, значение которого можно узнать из возвращаемой анонимной функции. При этом счетчик увеличится на 1. Если расширить функционал
|
|
|
+данного примера для чтения и декремента счетчика, получим, например:
|
|
|
+
|
|
|
+```javascript
|
|
|
+
|
|
|
+function makeCounter(){
|
|
|
+ var counter = 0;
|
|
|
+
|
|
|
+ function inc(){
|
|
|
+ return counter++;
|
|
|
+ }
|
|
|
+
|
|
|
+ function dec(){
|
|
|
+ return counter--;
|
|
|
+ }
|
|
|
+
|
|
|
+ function read(){
|
|
|
+ return counter;
|
|
|
+ }
|
|
|
+
|
|
|
+ return [inc,dec,read];
|
|
|
+}
|
|
|
+```
|
|
|
+Результатом выполнения `makeCounter` будет *массив функций*. Однако намного более наглядным будет создание именованного массива, т. е. объекта:
|
|
|
+
|
|
|
+```javascript
|
|
|
+
|
|
|
+function makeCounter(){
|
|
|
+ var counter = 0;
|
|
|
+
|
|
|
+ function inc(){
|
|
|
+ return counter++;
|
|
|
+ }
|
|
|
+
|
|
|
+ function dec(){
|
|
|
+ return counter--;
|
|
|
+ }
|
|
|
+
|
|
|
+ function read(){
|
|
|
+ return counter;
|
|
|
+ }
|
|
|
+
|
|
|
+ return {inc: inc, dec: dec, read: read};
|
|
|
+}
|
|
|
+```
|