Карманный справочник по JavaScript

Основы

Переменные и константы

Переменные

Позволяют сохранять, получать и изменять данные.

В JavaScript переменные можно создавать командой var, за которой следует имя переменной:

var x;              // Объявляем переменную
console.log(x);     // Выведет undefined
x = 20;             // Присваиваем одно значение
console.log(x);     // Выведет 20
x = 'сорок';         // Переопределение значения переменной
console.log(x);     // Выведет строку "сорок"

Способы записи названия переменной:

  • camelCase (верблюжья нотация) — все слова в названии переменной пишутся слитно и каждое новое слово начинается с большой буквы (myNumber, userName).
  • snake_case (змеиная нотация) — все слова разделяются нижним подчёркиванием (my_number, my_name).

Константы

Переменные которые не должны изменяться после объявления.

Именуются особенным образом: заглавными буквами с разделением слов через змеиный регистр (snake_case).

var EARTH_RADIUS = 6731;


Основные операторы

Минимальная единица языка, команда. Оператор принимает несколько значений, преобразует их и возвращает новое значение.

Операторы делятся по количеству принимаемых значений:

  • Унарные — операторы, которые работают с одним значением.
  • Бинарные — операторы, работающие с двумя значениями.
  • Тернарный — единственный в языке оператор, принимает на вход три значения. Возвращающий второе или третье переданное значение в зависимости от истинности первого.
    var result = true ? 1 : 0; // Вернет 1

Операторы делятся по типу возвращаемого значения на математические, строковые, логические (сравнения и булевой логики) и служебные.

Арифметические операторы

  • + cложение
  • - вычитание
  • * умножение
  • / деление
  • % остаток от деления
  • Инкремент (увеличение на единицу)
    i++ // i = i + 1
  • Декремент (уменьшение на единицу)
    i-- // i = i - 1
  • Сложение, совмещённое с присваиванием
    i += 2	// i = i + 2
  • Вычитание, совмещённое с присваиванием
    i -= 2	// i = i - 2
  • Умножение, совмещённое с присваиванием
    i *= 2	// i = i * 2
  • Деление, совмещённое с присваиванием
    i /= 2	// i = i / 2
  • Вычисление остатка от деления, совмещённое с присваиванием
    i %= 2	// i = i % 2

Если в операции сложения участвует строка, результат будет приведён к строке. Сложение строк — конкатенация.

Операторы сравнения

  • > — больше
  • < — меньше
  • >= — больше или равно
  • <= — меньше или равно

Операторы равенства

  • == — нестрогое равенство (с приведением типов). Сравнивает два значения, перед этим приводит одно из значений к типу другого. Если значения равны, возвращает true.
  • === — строгое равенство (без приведения типов). Сравнивает два значения. Если типы значений разные или значения не равны, возвращает false.
  • != — неравенство (с приведением типов). Сравнивает два значения, перед этим приводит одно из значений к типу другого. Если значения не равны, возвращает true.
  • !== — строгое неравенство (без приведения типов). Сравнивает два значения. Если типы значений разные или значения не равны, возвращает true.

Любые значения внутри проверок приводятся к булеву типу. Все числа кроме 0 — true, при этом 0 — false. Все строки, кроме пустой строки — true, пустая строка — false.

Логические операторы

  • && — «логическое И», возвращает true только в том случае, если оба условия, слева и справа от него, возвращают true.
  • || — «логическое ИЛИ», возвращает true если любое из условий слева или справа от него, возвращают true.
  • ! — «логическое отрицание», меняет булево значение выражения справа от него на противоположное.

Математические методы

  • Math.round() — округляет до целого к ближайшему целому.
  • Math.floor() — округляет до целого в меньшую сторону.
  • Math.ceil() — округляет до целого в большую сторону.
  • Math.random() — возвращает псевдослучайное число с плавающей запятой из диапазона [0, 1), то есть, от 0 (включительно) до 1 (но не включая 1).
  • Math.sqrt() — возвращает квадратный корень числа.
  • Math.pow(base, exponent) — возвращает base, возведённое в степень exponent.

Условные операторы

Условный оператор if

Условные операторы — конструкция языка, выполняющая определенный набор действий только при выполнении некоего логического выражения

Условие:

if (условие) {
  действия;
}

Условие с альтернативным действием:

if (условие) {
  действия;
} else {
  другие действия;
}

Вложенные условия:

if (условие1) {
  if (условие2) {
    действия;
  }
}

Здесь «условие» — это выражение, возвращающее true или false, а «действия» внутри фигурных скобок — это команды, которые выполняются, если условие удовлетворено.

Оператор вопросительный знак „?“

Вопросительный знак – единственный оператор, у которого есть три аргумента, поэтому его называют «тернарный оператор».

Тернарный оператор состоит из трех частей:

условие ? значение1 : значение2

Проверяется условие, затем если оно верно – возвращается значение1, если неверно – значение2, например:

access = (age > 14) ? true : false;

Циклы

Цикл for

Выполняет действия из тела цикла снова и снова, пока условие возвращает true.

for (var i = 0; i < 10; i++) {
  // повторяющиеся команды
}

Синтаксис

  • var i = 0; — подготовительная часть, исходное значение для счётчика. Задаётся с помощью var, как обычная переменная.
  • i < 10; — проверочная часть. Если условие возвращает true, цикл делает ещё одну итерацию иначе прекращает свою работу.
  • i++ — дополняющая часть, запускается на каждой итерации после выполнения кода из тела цикла. Меняет значение счётчика.

Цикл while

Действия будут выполняться снова и снова пока условие не вернёт false.

while (условие) {
  действия
}

Оператор break

Прерывает выполнение цикла.

while (total < victoryPoints) {
  if (misses >= 3) {
    break
  }
}

Оператор continue

Переход к следующей итерации цикла.

Функции

Функция — кусок кода, который можно написать один раз, а затем многократно использовать. Функция не просто содержит в себе значение, как переменная, а выполняет какое-то действие и решает какую-то задачу: считает, сравнивает, ищет.

var calculateSum = function (numberFirst, numberSecond) {
  var sum = numberFirst + numberSecond;
  return sum;
};

или

function calculateSum(numberFirst, numberSecond) {
  var sum = numberFirst + numberSecond;
  return sum;
}

calculateSum(); // Вернёт NaN
calculateSum(2); // Вернёт NaN
calculateSum(2, 5); // Вернёт 7
calculateSum(9, 5); // Вернёт 14

В этом примере:

  • calculateSum — имя, по которому можно обратиться к функции.
  • numberFirst, numberSecond — параметры функции.
  • return sum; — место кода, где происходит возвращение sum и выход из функции.
  • calculateSum(2, 5); — аргументы, которые передаются в функции при вызове. Порядок аргументов такой же, как у параметров функции. Первый аргумент 2 записывается в первый параметр numberFirst, аргумент 5 записывается в параметр numberSecond. Важно соблюдать порядок параметров при вызове функции, чтобы избежать неочевидных ошибок.

Возвращение из функции

Функция может выполнить код и отдать результат операций для дальнейшей работы с этим результатом. Он подставится в то место кода, где мы вызвали функцию.

var increaseByTwo = function (number) {
  var sum = 2 + number;
  return sum;
};

increaseByTwo(1); // Функция вернёт 3
increaseByTwo(2); // Функция вернёт 4

Несколько вещей, которые нужно знать:

  • Код, написанный на новой строке после return, не выполняется.
  • Функция не может вернуть сразу много значений, она возвращает только один результат.
  • Если внутри функции нет return или после return не указано, какое значение нужно вернуть, функция вернёт undefined, иными словами, ничего.

Области видимости

У каждой функции есть область видимости — все значения, доступные для этой функции.

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

Области видимости:

  • Локальная — в нее входят параметры функции и переменные, объявленные в ней.
  • Родительская — область видимости, в которой объявлена функция. Если функция находится в другой функции, она будет видеть её параметры и переменные.
  • Глобальная — набор значений доступный везде. Является объектом window, описывающим текущую вкладку браузера (исключая вложенные <iframe>, для каждого из них создается свой объект window).

Если внутри функции обратиться не к локальной переменной, JavaScript будет искать переменную снаружи, переходя наверх от уровня к уровню, пока не найдёт переменную. Если переменной не будет ни внутри функции ни снаружи, будет ошибка.

Так как функция может использовать переменные, объявленные снаружи, их можно переопределять.

function makeFunc() {
  var name = "Mozilla";
  function displayName() {
    console.log(name);
  }
  return displayName;
};

var myFunc = makeFunc();
myFunc(); // Выведет "Mozilla"
function makeAdder(x) {
  return function(y) {
    return x + y;
  };
};

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2));  // 7
console.log(add10(2)); // 12

Области видимости создаются только функциями. Поэтому, если переменная была создана в другой конструкции, например, в цикле, она будет доступна для чтения из функции.

Замыкания

Функция, которая помнит о своём окружении. Это функция + все значения вне локальной области видимости, которые она использует.

Благодаря замыканиям мы можем зафиксировать какое-то значение в функции, а использовать саму функцию позже.

var collectContainer = function (food) {
  return function () {
    console.log('Поел ' + food);
  };
};

var schoolkid = collectContainer('макароны');
schoolkid(); // Выведет 'Поел макароны'

Потеря окружения — ситуация, в которой функция-замыкание обращается к внешним переменным, которые были изменены или удалены.

Замыкания и асинхронность

Некоторые функции выполняются асинхронно, поэтому в момент выполнения кода значение переменной может уже измениться. Чтобы избавиться от этой проблемы, нужно создать отдельную область видимости. Так все переменные будут под контролем и замыкания не позволят потерять необходимые значения.

var thumbnails = document.querySelectorAll('.gallery__photo-preview');
var fullPhoto = document.querySelector('.full-photo');

var addThumbnailClickHandler = function (thumbnail, photo) {
  thumbnail.addEventListener('click', function () {
    fullPhoto.src = photo;
  });
};

for (var i = 0; i < thumbnails.length; i++) {
  addThumbnailClickHandler(thumbnails[i], photos[i]);
}

IIFE

Immediately Invoked Function Expression - это JavaScript функция, которая выполняется сразу же после того, как она была определена.

Функция становится мгновенно выполняющимся функциональным выражением. Переменные внутри функции не могут быть использованы за пределами ее области видимости.

(function () {
    statements
})();

Переменная, которой присвоено IIFE, хранит в себе результат выполнения функции, но не саму функцию.

var result = (function () {
    var name = "Barry";
    return name;
})();
// Immediately creates the output:
result; // "Barry"

Потеря окружения

Пример потери окружения:

var buttons = document.querySelectorAll('button');

for (var i = 0; i < buttons.length; i++) {
  var button = buttons[i];
  button.addEventListener('click', function (evt) {
    console.log(button.value); // button === buttons.length
  });
}

Решение 1. Cоздание изолированной области видимости:

var buttons = document.querySelectorAll('button');

var addClickListener = function (button) {
  button.addEventListener('click', function (evt) {
    console.log(button.value);
  });
}

for (var i = 0; i < buttons.length; i++) {
  var button = buttons[i];
  addClickListener(button);
}

Решение 2. Создание IIFE функции для ограничения области видимости:

var buttons = document.querySelectorAll('button');

for (var i = 0; i < buttons.length; i++) {
  (function (button) {
    button.addEventListener('click', function (evt) {
      console.log(button.value);
    });
  })(buttons[i]);
}

Разное

API

ApplicaMon Public Interface — набор доступных свойств и методов для решения определенной задачи. Часто реализуется в виде объектов. Как правило, свойства задают параметры решения, а методы определяют действия.

Примеры API:

  • DOM — работа с элементами страницы (в том числе SVG-графикой)
  • BOM — работа с браузером
  • Canvas — создание графики
  • XMLHppRequest — отправка запросов на сервер

console.log()

Выводит в консоль результаты операций: числа, строки (их надо заключать в кавычки).

console.log(x + 50);

.toLowerCase()

Возвращает значение строки, на которой он был вызван, преобразованное в нижний регистр.

str.toLowerCase()

.toUpperCase()

Возвращает значение строки, на которой он был вызван, преобразованное в верхний регистр.

str.toUpperCase()

Типы данных

Коротко о типах данных

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

Примитивные типы данных

Числа (number) — формат данных для представления числовой информации: целых, дробных чисел, бесконечности и неизвестного числового значения.

  • Записываются без дополнительных символов.
  • Поддерживается работа с целыми и дробными числами, дробная часть отделяется точкой.
  • Существует два дополнительных значения: Infinity и NaN.
  • Целые числа могут быть записаны в десятеричном или в шестнадцатеричном формате 0xFF.

Строки (string) — формат данных для представления текстовой информации.

  • Записываются внутри одинарных или двойных кавычек.

  • Называются строками, потому что переносы, пробелы и отступы являются обычными символами, поэтому весь текст хранится в виде одной длинной последовательности символов.
  • В случае, если в строке нужно использовать специальный символ, используется экранирование.
    '\tHello, I\'m a string\n\n';
  • Для строк существует только одна операция — строковое сложение или конкатенация. Для сложения строк используется оператор +.

Логический (boolean) тип данных — результат логических выражений. Имеет только два значения — истина (true) и ложь (false).

undefined — указывает, что значение не установлено.

null — указывает на неопределенное значение.

Сложные (составные) типы данных

Составные типы содержат несколько значений.

Объект (object) — состоит из множества пар «ключ-значение», порядок этих пар не важен.

{month: 'june', day: 15} // Объект
console.log({month: 'june', day: 15}); // Вывод объекта в консоль

Массив (array)разновидность объекта, хранит последовательность значений и порядок этих значений важен.

[1, 2, 3, 4, 5] // Массив
console.log([1, 2, 3, 4, 5]); // Вывод массива в консоль

Приведение типов

JavaScript — язык программирования сценариев (script)
 со слабой типизацией и динамическим приведением типов.

Приведение типов — если операнды переданные оператору разного типа, они автоматически приводятся к типу, в котором операцию можно выполнить. Тип, в который будут приведены операнды зависит от оператора

toString()

Приводит числовое значение к строковому типу.

var number = 1;

console.log(number.toString()); // Выведет строку: "1" (string)

parseInt()

Приводит строку к числовому значению.

var string = '10';

console.log(parseInt(string, 10)); // выведет число: 10 (number)

Второй аргумент — основание системы счисления, в которую переводим число.

parseFloat()

Приводит строку к числовому значению (число с плавающей точкой).

var string = '10.2';

console.log(parseFloat(string)); // выведет число: 10.2 (number)

typeof

Возвращает тип аргумента в виде строки.

typeof undefined // "undefined"

typeof 0 // "number"

typeof true // "boolean"

typeof "foo" // "string"

typeof {} // "object"

Массивы

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

В массиве можно хранить любые данные: строки, булевы значения, выражения, числа и даже другие массивы. Значения массива перечисляются через запятую. Каждая запятая создаёт новый элемент. Если поставить запятую и не указать значение, то образуется «дырка» — элемент которых содержит undefined.

var numbers = [1, 2, 3, 4, 5];

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

var numbers = [1, 2, 3, 4, 5];

console.log(numbers[1]); // Выведет в консоль 2

Нумерация элементов в массиве начинается с нуля: первый элемент массива идёт под номером ноль, второй — под номером один, третий — два и так далее.

Длина массива (или строки)

Для того что бы узнать длинну массива (или строки) используется команда .length, которая знает о количестве элементов в массиве (строке):

var numbers = [1, 2, 3, 4];

console.log(numbers.length); // Выведет в консоль 4

С помощью обращения к length можно получить последний элемент массива, даже если вы не знаете, сколько элементов в нём хранится:

someBigArray[someBigArray.length - 1];

Также можно узнать и длинну строки:

var string = 'Массив'; // Записывает строку в переменную

string.length; // Вернёт 6

Запись в массив по индексу

Запись в массив происходит так же, как и чтение — через обращение к элементу с помощью квадратных скобок:

var numbers = [];
var index = 1;

numbers[0] = 1;
numbers[index] = 2;

console.log(numbers); // Выведет [1,2]

Сортировка массива

var numbers = [12, 3, 7, 9, 10, 5];

for (var i = 0; i <= numbers.length - 2; i++) {
  var minValue = numbers[i];

  for (var j = i + 1; j <= numbers.length - 1; j++) {
    if (numbers[j] < minValue) {
      minValue = numbers[j];
      var swap = numbers[i];
      numbers[i] = minValue;
      numbers[j] = swap;
    }
  }
}

console.log(numbers); // Выведет [3, 5, 7, 9, 10, 12];

Массив с числами numbers сортируется по возрастанию элементов. На каждой итерации мы сравниваем minValue с остальными элементами массива. Если какой-то из них окажется меньше, чем minValue, он запишется в minValue, перезаписав старое значение, и переместится в начало массива. Переменная swap — вспомогательная переменная, с помощью, которой мы можем поменять элементы местами.

push()

Позволяет добавлять элементы в конец массива.

var names = [];

names.push('Кекс');
console.log(names); // Выведет ['Кекс']

var catName = 'Снежок';
names.push(catName);
console.log(names); // Выведет ['Кекс', 'Снежок']

indexOf()

Возвращает первый индекс, по которому данный элемент может быть найден в массиве или -1, если такого индекса нет. Такая операция называется поиском подстроки.

arr.indexOf(searchElement[, fromIndex = 0])
  • searchElement — Искомый элемент в массиве.
  • fromIndex — Индекс, с которого начинать поиск. Если индекс больше или равен длине массива, возвращается -1, что означает, что массив даже не просматривается. Если индекс является отрицательным числом, он трактуется как смещение с конца массива. Обратите внимание: если индекс отрицателен, массив всё равно просматривается от начала к концу. Если рассчитанный индекс оказывается меньше 0, поиск ведётся по всему массиву. Значение по умолчанию равно 0, что означает, что просматривается весь массив.

Метод indexOf() сравнивает искомый элемент searchElement с элементами в массиве, используя строгое сравнение (===).

Можем найти строку из одного символа, если обратиться ко всей строке, используя индекс:

var string = 'Меня зовут Кекс'; // Записываем строку в переменную

console.log(string[0]); // Ищем самый первый элемент в строке, вернёт 'М'

console.log(string[5]); // Ищем шестой элемент в строке, вернёт 'з'

Посмотрим, как работает команда indexOf():

string.indexOf('Кекс') // Ищем, есть ли в строке подстрока 'Кекс', вернёт 11

string.indexOf('Снежок') // Ищем, есть ли в строке подстрока 'Снежок', вернёт -1, такой подстроки нет

var searchString = 'Меня зовут'; // Ищем, есть ли в строке подстрока 'Меня зовут'

string.indexOf(searchString) // Вернёт 0

Объекты

Тип данных, который хранит в себе информацию в виде пар «ключ-значение». Каждый элемент сопоставлен со своим ключом и порядок элементов совсем неважен.

Ключи объектов должны быть строками.

Кавычки у ключей ставить необязательно, если ключ это одно слово.

Пара «ключ-значение» — называется свойством объекта. Свойства именуются по имени ключа. У термина свойство есть два синонима — поле и атрибут

Работа с объектами

var cat = {
  name: 'Кекс',
  age: 5
};

console.log(cat.name); // Выведет в консоль 'Кекс'
console.log(cat.age); // Выведет в консоль 5
console.log(cat.color); // Выведет undefined, такого ключа в объекте нет

cat.age++; // Увеличили возраст кота на 1
console.log(cat.age) // Выведет в консоль 6

cat.name = 'Рокки'; // Заменили снаружи значение свойства name
console.log(cat.name); // Выведет в консоль 'Рокки'

Передача по ссылке

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

var increaseBy2 = function(obj) {

obj.prop += 2;

return obj;
 };


var myObject = { prop: 2 };


console.log(increaseBy2(myObject)); // Вернет { prop: 4 }
console.log(myObject); // Вернет { prop: 4 }

Объект внутри функции increaseBy2 — тот же объект, что используется снаружи. При передаче объекта в функцию была передана ссылка на него, т.о. функция изменила исходный объект

Методы объектов

В объектах могут храниться любые типы данных, в том числе и функции. Такие свойства-функции называются методами объектов. Вызов метода записывается так: объект.метод().

Изнутри методов можно обращаться к свойствам и другим методам объекта с помощью ключевого слова this. Оно указывает на текущий объект и называется контекстом вызова.

Важная деталь: пока функция не вызвана, this не содержит никакого значения, контекст появляется только в момент вызова функции.

var cat = {
  name: 'Кекс',
  color: 'рыжий',
  age: 5,

  getGreeting: function() {
    return 'Мяу, привет! Меня зовут ' + this.name;
  }
};

console.log(cat.getGreeting()); // Выведет 'Мяу, привет! Меня зовут Кекс'

Скобочная и точечная нотация

Доступ к отдельным свойствам объектов осуществляется двумя способами — через точку или квадратные скобки.

Точечная нотация

var man = {
  name: 'Илья',
  age: 17
};

console.log(man.name);  // Выведет: Илья

man.age = 50; //Свойства можно не только читать, но и записывать.
console.log(man.age); // Выведет: 50

Скобочная нотация

Обращение через квадратные скобки отличается от обращения через точку тем, что в квадратные скобки нужно передавать строковое значение.

var man = {
  name: 'Илья',
  age: 17
};

console.log(man['name']);  // Выведет: Илья

man['age'] = 50; // Свойства можно не только читать, но и записывать.
console.log(man.age); // Выведет: 50

Скобочная нотация позволяет прочитать из объекта свойство, название которого записано в переменную:

var name = 'Кекс';

var catsFavoriteFood = {
  Кекс: 'рыба'
};

console.log(catsFavoriteFood.name); // Выведет в консоль undefined

console.log(catsFavoriteFood[name]); // Выведет в консоль 'рыба'

В качестве ключей в объекте можно использовать любые строки, даже строки с пробелами:

var cat = {
  'favorite food': 'Сметана'
};

console.log(cat.favorite food); // Вызовет ошибку

console.log(cat['favorite food']); // Отработает нормально

Мапы

Мапы или словари очень удобны в использовании. В нашем примере они хранят соотношение имени кота и лакомства, которое по вкусу именно ему.

var catsFavoriteFood = {
  Кекс: 'рыба',
  Рудольф: 'котлета',
  Снежок: 'сметана'
};

var printFavoriteFood = function (name) {
  return 'Моя любимая еда — ' + catsFavoriteFood[name]; // Используем скобочную нотацию
};

console.log(printFavoriteFood('Снежок')); // Выведет 'Моя любимая еда — сметана'

DOM

DOM-дерево

Document Object Model или объектная модель документа — способ представления разметки страницы в виде связанных между собой объектов.

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

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

DOM-дерево состоит из:

  • узел — любой элемент дерева
  • родитель — элемент, из которого растет узел
  • дети — элементы, которые растут из узла
  • корень — элемент из которого растет дерево, элемент без родителей
  • лист — элемент дерева, который не имеет детей

Дерево может иметь только один корень. У каждого элемента должно быть не более одного родителя

Виды обхода деревьев:

  • Depth-First Search — поиск в глубину
  • Breadth-First Search — поиск в ширину

Родительские элементы

.parentElement

Возвращает родителя узла DOM Element, или null если узел не имеет родителя, или его родитель не DOM Element.

parentElement = node.parentElement; // parentElement — родительский элемент текущего узла
if (node.parentNode) {
  // удаляем элемент из дерева
  node.parentNode.removeChild(node);
}

.parentNode

Возвращает родителя определенного элемента DOM дерева.

parentNode = node.parentNode; // parentNode — родитель текущего элемента

Соседние элементы

.previousElementSibling

Возвращает элемент стоящий перед применяемым, из списка дочерних элементов родителя или возвращает null, если таковых не имеется.

prevNode = elementNodeReference.previousElementSibling;

.previousSibling

Возвращает узел предшедствующий указанному в родительском элементе childNodes, или null, если указанный узел первый в своём родителе.

previousNode = node.previousSibling;

.nextElementSibling

Возвращает последующий элемент перед текущим, или null, если элемент является последним в своём родительском узле.

var nextNode = elementNodeReference.nextElementSibling;

.nextSibling

Возвращает узел, непосредственно следующий за данным узлом в списке childNodes его родительского элемента, или null если данный узел последний в этом списке.

nextNode = node.nextSibling;

Внутренние элементы

.children

Возвращает динамическую коллекцию HTMLCollection дочерних элементов узла. Структура данных, в которой хранятся дети children очень похожа на массив — у неё есть индексы и поле length.

// elList - живая коллекция, состоящая из дочерних элементов узла elementNodeReferencevar
elList = elementNodeReference.children;

.childNodes

Возвращает динамическую коллекцию NodeList дочерних элементов данного элемента. В отличие от .children, который содержит только элементы, например HTML- и SVG-теги, .childNodes содержит все возможные узлы — тексты, комментарии и пр.

// ndList - упорядоченная коллекция объектов элементов, которые являются детьми данного элемента.
var ndList = elementNodeReference.childNodes;

.contains

Указывает, является ли узел потомком данного узла.

node.contains( otherNode ) 
  • node — элемент который сравнивается.
  • otherNode — элемент с которым производится сравнение.

Возвращает true если otherNode является потомком node, или непосредственно самим node. В противном случае возвращает false.

Имя элемента

.tagName

Возвращает HTML-тег элемента ("div", "p", "a" и т.д).

// elementName это строка, содержащая название HTML-тега элемента element.
var elementName = element.tagName;

.nodeName

Возвращает имя текущего узла в виде строки.

var str = node.nodeName;

Поиск элементов в DOM

.getElementById()

Возвращает ссылку на элемент по его идентификатору (ID); может быть вызван только на всём документе; идентификатор является строкой, которая может быть использована для идентификации элемента; она может быть определена при помощи атрибута id в HTML или из скрипта.

element = document.getElementById(id);

.querySelector()

Принимает любой CSS-селектор и возвращает первый элемент внутри документа (используется предупорядоченный обход узлов в глубину до первого найденного узла), который совпадает с определенной группой селекторов.

// Поиск элемента по тегу
var list = document.querySelector('ul');

// Поиск последнего элемента из списка
var lastProduct = document.querySelector('li:last-child');

// Поиск элемента по классу
var price = document.querySelector('.price');

// Поиск третьего элемента из списка товаров
var thirdProduct = document.querySelector('.product:nth-child(3)');

.querySelectorAll()

Принимает любой CSS-селектор и возвращает статичную коллекцию списка элементов (поиск осуществляется в пределах указанного элемента), которые соответствуют указанной группе селекторов. Возвращает объект типа NodeList, содержащий все найденные элементы в том порядке, в котором они находятся в документе.

// Поиск всех элементов, подходящих по селектору
var listItems = document.querySelectorAll('.product');

Коллекция элементов DOM-дерева является живой коллекцией, т.е. любое изменение в DOM сразу же изменяет эту коллекцию.

.activeElement

Возвращает текущий сфокусированный элемент, то есть элемент, на котором будут вызываться события клавиатуры, если пользователь начнёт с неё ввод. Этот атрибут доступен только для чтения.

var curElement = document.activeElement;

Атрибуты DOM-элемента

Большинство HTML-атрибутов доступны в виде свойств DOM-элемента, и к ним можно обращаться напрямую. Исключения составляют те атрибуты, названия которых являются ключевыми или зарезервированными для будущих версий словами JS, например class или for у лейблов. Чтобы обратиться к классу, нужно воспользоваться свойством className, а чтобы прочитать лейбл, нужно воспользоваться свойством htmlFor.

.style

Используется для получения и установки инлайновых стилей. Стили не следует устанавливать непосредственно через свойство style (например elt.style = "color: blue;"), поскольку оно считается доступным только для чтения и атрибут style возвращает объект CSSStyleDeclaration который доступен только для чтения. Вместо этого стили могут быть установлены путем присвоения значений свойствам style. Для добавления определенных стилей для элемента без изменения других свойств стилей предпочтительно использовать отдельные свойства style (например elt.style.color = '...'). При использовании elt.style.cssText = '...' или elt.setAttribute('style','...') устанавливаются стили перезаписывая уже существующие. Объявленные стили сбрасываются присваиванием значения null.

// Устанавливает несколько стилей в одном выражении
elt.style.cssText = "color: blue; border: 1px solid black";
// Или
elt.setAttribute("style", "color:red; border: 1px solid blue;");

// Устанавливает определенный стиль оставляя другие значения стиля нетронутыми
elt.style.color = "blue";

.className

Отвечает за значение атрибута class элемента.

var pageHeading = document.querySelector('h1');
pageHeading.className = 'myclass';

.getAttribute()

Возвращает значение указанного атрибута элемента.

var pageHeading = document.querySelector('h1');
console.log(pageHeading.getAttribute('class')); // Вернет название класса pageHeading

.setAttribute()

Добавляет новый атрибут или изменяет значение существующего атрибута у выбранного элемента.

var pageHeading = document.querySelector('h1');
pageHeading.setAttribute('style', 'background: red;');

.classList

Специальный объект для работы с классами. Возвращает псевдомассив, содержащий все классы элемента.

var product = document.querySelector('.product'); // Когда ищем элемент по классу, используем точку
product.classList.add('product--sale'); // Но когда добавляем класс, точки нет!
var popup = document.querySelector('.popup'); // Перед названием селектора ставим точку
popup.classList.remove('popup--open'); // Перед названием класса точка не ставится

Методы:

  • classList.add() — Добавляет элементу указанные классы.
  • classList.remove() — Удаляет у элемента указанные классы.
  • classList.item() — Результат аналогичен вызову сlassList[Number].
  • classList.toggle() — Если класс у элемента отсутствует - добавляет, иначе - убирает. Когда вторым параметром передано false - удаляет указанный класс, а если true - добавляет.
  • classList.contains() — Проверяет, есть ли данный класс у элемента (вернет true или false).

Содержимое DOM-элемента

.textContent

Позволяет задавать или получать текстовое содержимое элемента и его потомков.

var text = element.textContent;
element.textContent = "Это просто текст";

.innerHTML

Устанавливает или получает разметку дочерних элементов. Позволяет создавать новые элементы на странице. Все элементы удаляются и создаются вновь каждый раз, когда мы вставляем новую разметку.

element.innerHTML = content;

В случае с .innerHTML браузер будет рисовать текст как HTML разметку. В то время как .textContent вставляет текст как есть.

.insertAdjacentHTML()

Разбирает указанный текст как HTML или XML и вставляет полученные узлы (nodes) в DOM дерево в указанную позицию (точечно). Данная функция не переписывает имеющиеся элементы, что предовращает дополнительную сериализацию и поэтому работает быстрее, чем манипуляции с innerHTML.

element.insertAdjacentHTML(position, text);

position указывает положение element, и может принимать одно из следующих значений:

  • 'beforebegin' — Перед element.
  • 'afterbegin' — Внутри element, перед первым дочерним элементом (потомком).
  • 'beforeend' — Внутри element, после последнего дочернего элемента.
  • 'afterend' — После element.

text — строка, которая будет проанализирована как HTML или XML и вставлена в DOM дерево документа.

insertAdjacentText()

Помещает заданный текстовый узел в указанную позицию относительно элемента, который передан в вызове метода.

element.insertAdjacentText(position, text);

position — позиция для вставки текста относительно элемента element. Указывается по аналогии с .insertAdjacentHTML().

text — текст, который будет помещен в заданную позицию.

.createElement()

Принимает на вход строку с именем тега и возвращает созданный DOM-элемент. Созданный элемент по умолчанию не находится в DOM-дереве и не отображается на странице.

var newDiv = document.createElement("div"); // создаем новый элемент div
newDiv.innerHTML = "<h1>Привет!</h1>"; // и добавляем в него немного контента

.removeChild

Удаляет дочерний элемент из DOM. Возвращает удаленный элемент.

var oldChild = element.removeChild(child);
element.removeChild(child);
  • child — дочерний элемент который будет удален из DOM.
  • element — родительский элемент удаляемого child.
  • oldChild — ссылка на удаляемый дочерний элемент. oldChild === child.

Удаленный дочерний элемент остается в памяти, но больше не является частью DOM. Вы можете повторно использовать удаленный элемент с помощью ссылки на объект - oldChild.

<div id="top" align="center">
  <div id="nested"></div>
</div>

// Удаление элемента с известным родителем
var d = document.getElementById("top");
var d_nested = document.getElementById("nested");
var throwawayNode = d.removeChild(d_nested);

// Удаление элемента без указания его родителя
var node = document.getElementById("nested");
if (node.parentNode) {
  node.parentNode.removeChild(node);
}

// Удаление всех дочерних элементов
var element = document.getElementById("top");
while (element.firstChild) {
  element.removeChild(element.firstChild);
}

.remove()

Удаляет узел из дерева DOM.

То, что элемент удален из DOM, еще не значит, что он удален совсем! Он остался объектом и исчезнет только тогда, когда исчезнут все ссылки на него.

Node.remove();

Node - любой узел DOM

.appendChild()

Добавляет элемент в конец списка дочерних элементов родителя. Если элемент уже существует он удаляется из текущего родителя и вставляется заново. Возвращает ссылку на добавленный узел(элемент).

var list = document.querySelector('.cards');

var card = document.createElement('li'); // Создаём новый элемент

card.classList.add('card');

list.appendChild(card); // После вызова этого метода новый элемент отрисуется на странице

.insertBefore()

Добавляет элемент в список дочерних элементов родителя перед указанным элементом. Если вторым параметром передать null, то добавляемый элемент встанет в конец блока.

var insertedElement = parentElement.insertBefore(newElement, referenceElement);
  • insertedElement — Вставленный элемент.
  • parentElement — Родитель для нового элемента.
  • newElement — Элемент для вставки.
  • referenceElement — Элемент, перед которым будет вставлен newElement.
<div id="parentElement">
  <span id="childElement">foo bar</span>
</div>

// Создаем новый <span>
var sp1 = document.createElement("span");

// Получаем ссылку на элемент, перед которым мы хотим вставить sp1
var sp2 = document.getElementById("childElement");
//Получаем ссылку на родителя sp2
var parentDiv = sp2.parentNode;

// Вставляем sp1 перед sp2
parentDiv.insertBefore(sp1, sp2);

.replaceChild

Заменяет дочерний элемент на выбранный. Возвращает замененный элемент.

replacedNode = parentNode.replaceChild(newChild, oldChild);
  • newChild — элемент на который будет заменен oldChild. В случает если он уже есть в DOM, то сначала он будет удален.
  • oldChild — элемент который будет заменен.
  • replacedNode — замененный элемент. Тоже самое что и oldChild.
<div>
 <span id="childSpan">foo bar</span>
</div>

// Создаем новый пустой элемент
// without an ID, any attributes, or any content
var sp1 = document.createElement("span");

// Присваиваем ему id 'newSpan'
sp1.setAttribute("id", "newSpan");

// Создаем строку.
var sp1_content = document.createTextNode("new replacement span element.");

// Добавляем контент в созданный нами узел
sp1.appendChild(sp1_content);

// создаем ссылку на существующий элемент который будем заменять
var sp2 = document.getElementById("childSpan");
var parentDiv = sp2.parentNode;

// заменяем существующий элемент sp2 на созданный нами sp1
parentDiv.replaceChild(sp1, sp2);

// Результат:
<div>
 <span id="newSpan">new replacement span element.</span>
</div>

.compareDocumentPosition

Сравнивает позицию текущего узла и другого узла в любом другом документе.

node.compareDocumentPosition(otherNode);
  • node — это узел, который сравнивается.
  • otherNode — это узел, с которым идет сравнение.

Возвращаемое значение (битовая маска) вычисляется как отношение, которое имеется между otherNode и node.

Шаблонизация

.createDocumentFragment()

Создает новый пустой DocumentFragment. Позволяет сгруппировать однотипные или разнотипные элементы и вставить их все вместе.

var fragment = document.createDocumentFragment();

fragment это ссылка на пустой объект DocumentFragment.

// Создаем 6 элементов и вставляем их за 1 раз
var firstPool = document.querySelector('.pool');

var fragment = document.createDocumentFragment();

for (var i = 0; i < 6; i++) {
  var newElement = document.createElement('div');
  newElement.className = 'el';
  newElement.innerHTML = '<span>' + i + '</span>';

  fragment.appendChild(newElement);
}

firstPool.appendChild(fragment);

cloneNode

Возвращает дубликат узла, из которого этот метод был вызван.

var dupNode = node.cloneNode(deep);
  • node — Узел, который будет клонирован.
  • dupNode — Новый узел, который будет клоном node.
  • deep (необязательный) — true, если дети узла должны быть клонированы или false для того, чтобы был клонирован только указанный узел.
var p = document.getElementById("para1");
var p_prime = p.cloneNode(true);

<template>

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

<template id="element-template">
    <p class="text"></p>
</template>
// Находим элемент для вставки в него копии шаблона
var div = document.querySelector('.div');

// Создаем элемент из шаблона
var template = document.querySelector('#element-template').content.querySelector('div');

// Клонируем шаблон с вложенным содержимым
var element = template.cloneNode(true);

// Вставляем склонированный шаблон
div.appendChild(element);

События

События — это механизм, который позволяет описать реакцию на определённые асинхронные действия пользователя или браузера. Например, ввод данных пользователем, окончание загрузки или наступление ошибки.

Всплытие и перехват

Существует три стадии прохода события:

  • Стадия перехвата (capturing stage) — событие сначала идет сверху вниз.
  • Стадия цели (target stage) — событие достигло целевого элемента.
  • Стадия всплытия (bubbling stage) — после этого событие начинает всплывать.

То есть, при клике событие путешествует по цепочке родителей сначала вниз к элементу («погружается»), а потом наверх («всплывает»), по пути задействуя обработчики.

В современных браузерах по умолчанию все обработчики событий регистрируются в фазе всплытия.

Всплытие идёт прямо наверх, до элемента <html>, а затем до document, а иногда даже до window, вызывая все обработчики на своем пути.

Всплывают почти все события. Например, события focus, blur, invalid не всплывают.

Event.stopPropagation()

Прекращает дальнейшую передачу (всплытие) текущего события. Event.stopPropagation() препятствует продвижению события дальше, но на текущем элементе все обработчики отработают.

evt.stopPropagation();

Event.eventPhase

Отображает текущую фазу процесса обработки события (погружение = 1, всплытие = 3).

Делегирование

Заключается в том, что если у нас есть много элементов, события на которых нужно обрабатывать похожим образом, то вместо того, чтобы назначать обработчик каждому – мы ставим один обработчик на их общего предка. Из него можно получить целевой элемент event.target, понять на каком именно потомке произошло событие и обработать его.

Event

Представляет собой любое событие, которое происходит в DOM; некоторые из них генерируемые пользователем (клик мышью или нажатие клавиши на клавиатуре), а некоторые - генерируемые API (события, обозначающие завершение процесса анимации, приостановка видео и т.д.). Существует много типов событий, некоторые из них используют интерфейсы, базирующиеся на главном интерфейсе Event. Содержит общие свойства и методы для всех событий.

Объект Event — также называемый объект события, параметр функции-обработчика. Он всегда передаётся браузером в функцию .addEventListener() в момент наступления события.

Чтобы использовать Event, достаточно указать этот объект параметром функции-обработчика и написать инструкции. Принято называть параметр сокращённо — evt.

Сравнение разных Event Targets

Event.target

Ссылка на объект (элемент), который был инициатором события. Он может отличаться от event.currentTarget, если обработчик события вызывается во время всплытия (bubbling) или захвата события.

// Предполагается, что есть переменная 'list', содержащая экземляр элемента <ul>
function hide(evt) {
  evt.target.style.visibility = 'hidden';
}

list.addEventListener('click', hide, false);

Event.currentTarget

Определяет элемент, в котором в данный момент обрабатывается событие, при движении события внутри DOM. Всегда совпадает с текущим элементом, в отличие от свойства event.target, идентифицируещее элемент, на котором событие возникло.

Event.currentTarget === this

Event.preventDefault()

Отменяет действие элемента по умолчанию.

link.addEventListener('click', function(evt) {
  evt.preventDefault(); // Отменяем действие по умолчанию
  console.log('Произошёл клик'); // Добавляем инструкции для события клика
});

.addEventListener()

Регистрирует определенный обработчик события, вызванный на EventTarget. EventTarget должен быть либо существующим элементом в документе, либо Document, либо Window, либо любым другим объектом, который поддерживает события.Обработчик события — это функция, которая будет запущена, когда наступит соответствующее событие.

button.addEventListener("click", function, true);

.addEventListener() принимает на вход три параметра:

  • Первый параметр 'click' — строковое название (тип) события. Названия всех событий можно посмотреть здесь.
  • Второй параметр function — функция-обработчик (может быть анонимной), которая создаётся в момент выполнения функции .addEventListener(), в ней записаны инструкции, которые выполнятся, только когда произойдёт событие.
  • Третий параметр — аргумент true (событие будет перехвачено по дороге вниз) или false (по умолчанию, событие будет поймано при всплытии).
  • button — элемент, на котором мы хотим «слушать» событие.
  • addEventListener — функция добавления обработчика события на элемент.

Существует два способа именования обработчиков:

  • В первом способе обработчик именуется как объект + событие + Handler. Например buttonClickHandler — этот обработчик реагирует на клики (click) по объекту кнопки (button).
  • Второй вариант именования обработчиков — on + объект + событие. Например onButtonClick.

Стоит помнить разницу между обращением к функции и запуском ее кода. Для того, чтобы обратиться к функции, достаточно просто написать ее название. Если же за названием следуют круглые скобки — код функции выполнится немедленно, и в качестве обработчика в .addEventListener() будет передан результат работы этой функции.

Функции, которые создаются в момент передачи и не имеют имени, называются анонимными функциями.

С помощью метода .addEventListener() можно регистрировать сколько угодно обработчиков одного и того же события на одном и том же элементе. Обе функции будут выполняться при щелчке элемента:

myElement.addEventListener('click', functionA);
myElement.addEventListener('click', functionB);

.removeEventListener()

Удаляет обработчик события, который был зарегистрирован при помощи .addEventListener(). Обработчик определяется типом события, самой функцией обработки события, и дополнительными параметрами, переданными при регистрации обработчика.

Анонимную функцию-обработчик удалить невозможно, чтобы корректно удалить обработчик, нужно обратиться к той же самой функции, которая была передана в качестве параметра в .addEventListener(). Это возможно только в том случае, если функция была создана заранее и не является анонимной.

var onPopupEscPress = function(evt) {
  if (evt.keyCode === 27) {
    closePopup();
  }
};

var closePopup = function() {
  setup.classList.add('hidden');
  document.removeEventListener('keydown', onPopupEscPress);
};

'click'

Событие click срабатывает, когда кнопка указывающего устройства (например, основная кнопка мыши) одновременно нажата и отпущена, когда указатель находится внутри элемента. Т.е. когда произошло mousedown и затем mouseup.

KeyboardEvent

Объекты KeyboardEvent описывают работу пользователя с клавиатурой. Каждое событие описывает клавишу; тип события (keydown, keypress или keyup) определяет произведённый тип действия.

Событие «нажатие на клавишу» носит название — 'keydown'. Такое событие срабатывает при нажатии на любую клавишу. Слушать это событие можно только на элементах, которые имеют состояние фокуса: поля ввода, кнопки, элементы с атрибутом tabindex, документ. При нажатии фокус должен находиться на соответствующем элементе.

Если необходимо поймать нажатие какой-то конкретной клавиши, можно обратиться к свойству keyCode объекта event. Это свойство содержит код нажатой клавиши.

document.addEventListener('keydown', function(evt) {
  if (evt.keyCode === 27) { // Проверяем, что код клавиши равен 27
    // Код отсюда выполнится только при нажатии ESC
  }
});

В настоящий момент свойство keyCode устарело, вместо него стоит использовать KeyboardEvent.code.

Для встроенных активных элементов (input, button, a), не нужно описывать дополнительно поведение работы с клавиатурой, достаточно просто добавить обработчик события 'click'.

Формы и валидация

Интерфейс HTMLFormElement предоставляет методы для создания и изменения элементов <form> он наследуется от свойств и методов интерфейсаHTMLElement.

Методы:

  • .reset() — восстанавливает стандартные значения всем элементам формы. Данный метод выполняет действие идентичное нажатию кнопки имеющей тип reset.
    document.getElementById('myform').reset();
  • .reportValidity() — возвращает true если все дочерние элементы прошли проверку. Когда возвращается false, по каждому дочернему элементу не прошедшему проверку генерируется событие invalid и пользователю сообщаются проблемы проверки.
    HTMLFormElement.reportValidity()

<input>

Используется для создания интерактивных элементов управления в веб-формах для принятия данных от пользователя.

Атрибуты

value

Для получения текста из поля ввода нужно обратиться к свойству поля ввода value. Оно хранит информацию, введённую в поле.

// Находим input
var newItemTitle = newItemForm.querySelector('.add-form-input');

// Сохраняем введенный текст
var taskText = newItemTitle.value;

'change'

Событие 'change' вызывается для элементов <input>, <select> и <textarea>, когда изменение фиксируется в значении элемента пользователем (когда состояние поля меняется). В отличие от входного события, событие изменения не обязательно запускается для каждого изменения значения элемента.

element.addEventListener('change', function () {
  …
});

'submit'

Событие 'submit' срабатывает при отправке <form>.

element.addEventListener('submit', function () {
  …
});

Событие 'submit' запускается для самого элемента <form>, а не для любого элемента <button> или <input type = "submit"> внутри него.

Событие 'submit' срабатывает только тогда, когда пользователь нажимает кнопку отправки (<button> или <input type = "submit">) в форме. Событие не вызывается при непосредственном вызове метода form.submit().

Если не нужно отправлять форму в каких-то случаях, отмените действие по умолчанию с помощью preventDefault.

'invalid'

Событие 'invalid' запускается, когда отправляемый элемент был проверен, но его содержимое не удовлетворило установленные ограничения. Валидность отправляемого элемента проверяется до отправления формы или после вызова методаcheckValidity() на элементе.

'input'

Событие 'input' срабатывает, когда значение элемента <input>, <select> или <textarea> было изменено.

ValidityState

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

Возможные значения ValidityState:

  • tooLong — Возвращает true если значение элемента больше заданной атрибутом maxlength максимальной длины элемента; иначе будет false. Если возвращает true, элемент будет соответствовать :invalid и CSS псевдоклассу :out-of-range.
  • tooShort — Возвращает true если значение элемента меньше заданной атрибутом minlength минимальной длины элемента; иначе будет false.
  • valueMissing — Возвращает true если элемент не имеет значения, но является обязательным полем; в противном случае false. Если возвращает true, элемент будет соответствовать CSS псевдоклассу :invalid.
  • badInput — введено неправильное значение
  • customError — задано кастомное сообщение об ошибке
  • patternMismatch — не соответствует паттерну
  • rangeOverflow — больше значения max
  • rangeUnderflow — меньше значения min
  • stepMismatch — значение не попадает в step
  • typeMismatch — не совпадает тип
  • valid — валидно ли поле
userNameInput.addEventListener('invalid', function (evt) {
  if (userNameInput.validity.tooShort) {
    userNameInput.setCustomValidity('Имя должно состоять минимум из 2-х символов');
  } else if (userNameInput.validity.tooLong) {
    userNameInput.setCustomValidity('Имя не должно превышать 25-ти символов');
  } else if (userNameInput.validity.valueMissing) {
    userNameInput.setCustomValidity('Обязательное поле');
  } else {
    userNameInput.setCustomValidity(''); // сбрасываем значение поля, если оно стало корректно
  }
});

Можно не только переопределять стандартное поведение валидации, а также расширять его и добавлять свои собственные обработчики форм.

userNameInput.addEventListener('input', function (evt) {
  var target = evt.target;
  if (target.value.length < 2) {
    target.setCustomValidity('Имя должно состоять минимум из 2-х символов');
  } else {
    target.setCustomValidity('');
  }
});

.setCustomValidity()

Устанавливает специальное сообщение для выбранного элемента. Если элемент не имеет пользовательской ошибки в параметре укажите пустую строку.

selectElt.setCustomValidity(string);

Перемещение элемента

Drag and drop

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

Drag and drop (на русском)

HTML Drag and Drop API (на английском)

MouseEvent

Представляет собой событие, которое происходит в результате взаимодествия пользователя с манипулятором (например, мышью). Наиболее частые из таких событий: click, dblclick, mouseup, mousedown.

Свойства:

  • .clientX — является горизонтальной координатой в пределах клиентской области приложения, на которой произошло событие (в отличие от координат внутри страницы).
    var x = evt.clientX
  • .clientY — является вертикальной координатой в пределах клиентской области приложения, на которой произошло событие (в отличие от координат внутри страницы).

'mousedown'

Событие mousedown срабатывает, когда кнопка указывающего устройства (к примеру, мыши) нажата над элементом.

'mousemove'

Событие mousemove вызывается для элемента, когда указательное устройство (обычно мышь) перемещается, когда в нем находится курсор.

'mouseup'

Событие mouseup вызывается у Element, когда кнопка указательного устройства (такого как мышь или трекпад) отпускается, когда указатель находится внутри него.

.offsetTop

Возвращает расстояние текущего элемента по отношению к верхней части узла.

topPos = element.offsetTop;

topPos - количество пикселей на которые делается отступ с верху, отсносительно родительского элемента.

.offsetLeft

Возвращает смещение в пикселях верхнего левого угла текущего элемента от родительского узла.

Прочее

Отладка

Часть процесса программирования, во время которой разработчик пытается найти и устранить ошибки в программе.

  • debugger — программа, проверяющая процесс выполнения кода. Показывает состояние программы по мере выполнения каждого выражения.
  • breakpoint — точка останова. Указание отладчику с какого момента начинать слежение за выполнением программы. Ставится на строку.

JavaScript в браузере

Подключение скриптов на страницу

Скрипты подключаются к странице с помощью тега script двумя способами:

  • Инлайновый код. Код пишется внутри тега script.
    <body>
      …
      <script>console.log('Я — инлайновый скрипт');</script>
    </body>
  • Внешний файл с кодом. Тегу script добавляется атрибут src, в котором указывается путь до файла со скриптом.
    <body>
      …
      <script src="script.js"></script>
    </body>

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

Скрипты выполняются по мере подключения на страницу. Если за тегом script находится разметка, она не отрисуется пока не выполнится скрипт (в случае с инлайновым кодом) или пока он не скачается с внешнего ресурса и не будет выполнен (при подключении внешнего файла).

Синхронное и асинхронное подключение скриптов:

  • Если у тега script указан атрибут async, то скрипт не блокирует выполнение страницы. Скрипт с таким атрибутом начинает загружаться сразу как встретится в разметке, а выполнится как только загрузка закончится.
  • Атрибут defer работает как async с той разницей, что код выполняется после полной загрузки страницы.

Локальные скрипты приложения, которые работают с разметкой, лучше подключать внизу страницы, перед закрывающим тегом </body> потому что на момент их исполнения, элементы из DOM-дерева будут отрисованы и доступны.

Библиотеки, счетчики и прочие внешние ресурсы, как правило, подключаются в </head>. Это гарантирует, что библиотека всегда будет доступна для других скриптов, вне зависимости от того, где и как они были подключены.

Canvas

<canvas>

Документация

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

<canvas id="canvas"></canvas>

Для начала, нужно получить доступ к самому тегу <canvas>, и получить «контекст отрисовки».

// DOM-элемент канваса
var canvas = document.getElementById('canvas');

// Контекст отрисовки
var ctx = canvas.getContext('2d');

fillRect

Отрисовывает закрашенный прямоугольник.

Первые два параметра задают координаты левого верхнего угла, третий и четвёртый — ширину и высоту объекта.

ctx.fillRect(0, 0, 300, 150);

fillStyle

Задает стиль заливки, вызывается перед отрисовкой фигуры.

Цвет заливки задается так же, как это делается в CSS — с помощью названия цвета, HEX-кода, rgb или rgba.

ctx.fillStyle = 'blue';

Последний заданный fillStyle будет применён ко всем вызовам fill (или к отрисовке заранее закрашенных фигур). Чтобы залить следующую фигуру другим цветом, нужно переопределить fillStyle.

ctx.fillStyle = 'blue';
ctx.fillRect(0, 0, 200, 150); // Закрасит синим

ctx.fillStyle = 'lightgreen';
ctx.fillRect(210, 40, 30, 30); // Закрасит светлозеленым

Для заливки фигуры градиентом в fillStyle нужно записать объект, полученный с помощью метода контекста ctx.createLinearGradient или ctx.createRadialGradient. Цвета градиентов задаются с помощью метода addColorStop у объекта градиента.

var gradient = ctx.createLinearGradient(0, 0, 300, 150);
gradient.addColorStop(0, 'green');
gradient.addColorStop(1, 'rgba(0, 255, 0, 0)');

ctx.fillStyle = gradient;
ctx.fillRect(0, 0, 300, 150);

fill

Заливает отрисованный контур. Контур зальётся так, как это указано в свойстве fillStyle.

ctx.fill();

Существуют два способа заливки:

  • 'nonzero' — по умолчанию, закрашивается все, что находится внутри фигуры.
  • 'evenodd' — закрашивается только та часть фигуры, которая не пересекает сама себя.
ctx.fill('nonzero');
ctx.fill('evenodd');

strokeStyle

Задает стиль обводки фигуры.

ctx.strokeStyle = 'blue';

stroke

Рисует обводку контура фигур цветом strokeStyle.

ctx.stroke();

clearRect

Используется для очистки холста.

ctx.clearRect(0, 0, 300, 150);

Сложные фигуры

Сложные фигуры рисуются с помощью контуров. Контур — это описание формы фигуры, без заливки или обводки. Контуры описываются с помощью простых фигур, а потом управление, например, заливка или обводка, производится целиком над фигурами.

Начало контура задается методом beginPath, конец контура closePath, все, что будет нарисовано между этими вызовами, будет считаться одной фигурой.

ctx.beginPath(); // начало контура
ctx.moveTo(100, 100); // перемещает начальную точку нового фрагмента контура
ctx.lineTo(150, 100); // рисует линию из последней точки
ctx.bezierCurveTo(140, 90, 110, 90, 100, 100); //рисует кривую Безье
ctx.closePath(); //конец контура
ctx.stroke(); // рисует обводку
ctx.fill(); // заливает отрисованный контур

Работа с текстом

Вывод текста осуществляется одним из двух методов: fillText или strokeText, которые выводят, соответственно, залитый или обведённый текст.

ctx.fillText('Привет', 0, 10); // выводит залитый текст
ctx.strokeText('Привет', 0, 10); // выводит обведённый текст

Параметры текста задаются свойствами контекста font, textAlign и textBaseline.

ctx.font = '30px Tahoma';
ctx.textBaseline = 'hanging'; // выравнивает текст
ctx.fillText('Текст', 0, 10);

Особенность текстов на канвасе: они не переносятся.

Чтобы написать текст с переносами, нужно каждую новую строку вынести в отдельный вызов метода fillText (или strokeText). Можно автоматизировать этот процесс, написав функцию, разбивающую текст на строчки, если они не помещаются в указанную ширину.

Размеры

Размер канваса по умолчанию — 300×150px. Координатная сетка канваса изначально имеет такой же размер.

Если изменить размеры канваса, используя css, то изменятся внешние размеры блока, а координатная сетка останется прежней — 300×150px.

Чтобы изменить и размеры канваса и координатную сетку, нужно воспользоваться свойствами width и height DOM-элемента канваса.

<canvas id="canvas" width="120" height="120"></canvas>

Алгоритмы

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


          

Модули

Модуль

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

Модуль это:

  • функция — отдельная часть файла, которая может несколько раз использоваться в одном файле
  • узкоспециализированный код
 — код, который решает ровно одну задачу (например, валидация формы или работа всплывающего окна)
  • несколько функций, записанных в объект
 — (неймспейс, пространство имен) например, объект Math. Набор функций и значений из одной области
  • набор функций (библиотека)
 — полезный набор инструментов, который может переноситься из проекта в проект

Области видимости в модулях:

  • Локальная — используется для служебных функций и значений, которыми нельзя пользоваться снаружи
  • Глобальная — интерфейс функции. То, чем можно пользоваться снаружи модуля

Инкапсуляция

Изоляция служебных переменных, объектов, функций с целью сокрытия доступа и предотвращения возможности управления ими.

  • Локальные константы — служебные значения, которые используются только в одном модуле
  • Вспомогательные функции
 — функции, которые используются во внутренних расчётах, но снаружи не нужны
  • Служебные переменные
 — вспомогательные переменные, названия которых могут пересекаться с названиями переменных в других модулях

Экспорт

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

Порядок подключения модулей: сначала подключаются модули, которые не зависят от других модулей и только потом подключаются зависимые модули.

Чтобы воспользоваться значениями одного модуля из другого необходимо экспортировать их в глобальную область видимости window.

Вариант 1:

// Модуль util.js
(function () {
  var ESC_KEYCODE = 27;

  window.util = {
    isEscEvent: function (evt, action) {
      if (evt.keyCode === ESC_KEYCODE) {
        action();
      }
    }
  };
})();

Вариант 2:

// Модуль util.js
window.util = (function () {
  var ESC_KEYCODE = 27;

  return {
    isEscEvent: function (evt, action) {
      if (evt.keyCode === ESC_KEYCODE) {
        action();
      }
    }
  };
})();

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

// Модуль dialog.js
(function () {
  console.log(window.util.ESC_KEYCODE);
  console.log(window.util.ENTER_KEYCODE);
})();

Объекты для хранения значений именуются также как сам модуль. Если имя модуля состоит из нескольких слов, то они записываются через дефис, а объект в котором хранится экспортируемое значение записывается по правилам именования переменных — через camelCase.

// Модуль create-element.js
(function () {
  window.createElement = function() {
    // здесь какой-то код
  };
})();

Алгоритм разделения проекта на модули

  1. Разделить файлы логически, по тому, что они делают
 — сделать так, чтобы код решающий разные, непересекающиеся задачи, хранился в разных файлах.
  2. Найти повторяющийся код внутри модулей, вынести в функцию
 — принцип DRY — не нужно писать один и тот же код несколько раз. Если задача уже была решена, можно воспользоваться готовым решением.
  3. Eсли один и тот же код используется в нескольких файлах — вынести его в отдельный модуль
 (расширение принципа DRY на уровень проекта).
  4. Убедиться, что в модулях используется пространство имен
 (один модуль — одно значение).

Решения задач HTML Academy

Знакомство с JavaScript

1. Конвертер валют

var rublesAmount = euroAmount * euroRate + dollarAmount * dollarRate;

2. Считаем долги

var debtAmount = (travelCost - balance) * 2;

3. Быстрее всех

var flightTime = Math.round(flightDistance / averageSpeed);

4. Путешествие продолжается

var routeTime = Math.round(routeDistance * 1.6 / averageSpeed);

5. Жара в Висконсине

var celsiusTemperature = 5 / 9 * (farenheitTemperature - 32);

6. Контроль показателей — ключ к победе!

var bodyMassIndex = Math.round(weight / (length * length));
var fatPercent = Math.round(fatMass / weight * 100);

7. Пробежки по треугольному парку

var hypotenuse = Math.round(Math.sqrt(firstLeg * firstLeg + secondLeg * secondLeg));

var perimeter = firstLeg + secondLeg + hypotenuse;

8. Эффективная ЧСС

var pulseAtWorkout = Math.round(((220 - age) - pulseAtRest) * (intensity / 100)
+ pulseAtRest);

9. Кубики куются на кухне

var hhh = 88.362 + (13.397 * weight) + (4.799 * length) - (5.677 * age);

var calorieRate = Math.round(hhh * activityRate);
var proteins = Math.round(calorieRate * 0.4);
var fats = Math.round(calorieRate * 0.25);
var carbohydrates = Math.round(calorieRate * 0.35);

Условия

1. Неприличный вопрос

if (age <= 1) {
  ageGroup = 'Котята';
}

if (age > 1 && age <= 3) {
  ageGroup = 'Молодые коты';
}

if (age > 3 && age <= 7) {
  ageGroup = 'Коты средних лет';
}

if (age > 7) {
  ageGroup = 'Почтенные коты';
}

2. Умные весы

if (weight < 4) {
  recommendation = 'Пора перекусить';
}

if (weight >= 4 && weight <= 5.5) {
  recommendation = 'Вес в норме';
}

if (weight > 5.5) {
  recommendation = 'Пора на тренировку';
}

3. FizzBuzz

if (number % 3 == 0) {
  taskResult = 'Fizz';
}

if (number % 5 == 0) {
  taskResult = 'Buzz';
}

if (number % 3 == 0 && number % 5 == 0) {
  taskResult = 'FizzBuzz';
}

if (number % 3 !== 0 && number % 5 !== 0) {
  taskResult = number;
}

4. Творческий доход

if (buy < 1000) {
  discountedBuy = buy;
}

if (buy >= 1000 && buy < 3000) {
  discountedBuy = buy * 0.95;
}

if (buy >= 3000 && buy < 5000) {
  discountedBuy = buy * 0.9;
}

if (buy >= 5000) {
  discountedBuy = buy * 0.85;
} 

5. Путь к молоку

if (time >= 8 && time < 13 || time >= 14 && time < 19) {
  goToDairy = true;
} else if (time === 13) {
  goToStore = true;
} else if (time === 7 || time >= 19 && time < 20) {
  goToMarket = true;
}

6. Длительность прогулки

if (!itsRaining && temperature > 0 && temperature <= 35 ) {

  if (temperature === 20) {
    minutes = 20;
  } else if (temperature < 20) {
    minutes = 20 - (20 - temperature);
  } else if (temperature > 20) {
    minutes = 20 - (temperature - 20);
  }

} else {
  minutes = 0;
}

Циклы

1. Геометрическая прогрессия

console.log(startNumber);
for (i = 1; i < quantity; i++) {
  console.log(startNumber *= multiplier);
}

2. Сумма чисел

for (var i = 1; i <= lastNumber; i++) {
  sum += i;
}

3. Произведение чётных

for (var i = 1; i <= lastNumber; i++) {
  if(i % 2 === 0) {
    multiplicationResult *= i;
  }
}

4. Делители

for (var i = 2; i < number; i++) {
  if (number % i === 0) {
    console.log(i);
  }
}

5. Сколько цифр?

while (number / 10 > 0.1) {
  number /= 10;
  quantity++;
}

6. Запасы протеина

for (var i = 1; i <= days; i++) {
  if (i % period === 0) {
    if (i % 7 === 0 || (i + 1) % 7 === 0) {
      total += weekendAmount;
    } else {
      total += workDayAmount;
    }
  }
}

7. Палиндром

var poly = 501;
var ylop = 0;
var isPalindrome = false;

var a = poly;

while (a >= 1) {
  ylop = ylop * 10 + a % 10;
  a = a / 10 - (a % 10) / 10;
}

if (ylop === poly) {
  isPalindrome = true;
}

Массивы

1. Смузи, маффин, гироскутер

order = 'Основа — ' + liquids[chosenLiquid - 1] + ', фрукт — ' + fruits[chosenFruit - 1] +
', зелень — ' + greens[chosenGreen - 1];

2. Список покупок

for (var i = 0; i < groceries.length; i++) {
  if (i < groceries.length - 1) {
  shoppingList += groceries[i] + ", ";
  } else {
    shoppingList += groceries[i];
  }
}

3. В поисках элемента

var lastIndex = -1;

for (var i = 0; i < numbers.length; i++) {
  if (numbers[i] === number) {
    lastIndex = i;
  }
}

4. Собираемся в отпуск

for (var i = startIndex; i < startIndex + quantity; i++) {
  chosenLuggage.push(luggage[i]);
}

5. Список для чтения

for (var i = 0; i < books.length; i++) {
  if (books[i].length <= maxNumber && books[i].length >= minNumber) {
    filteredBooks.push(books[i]);
  }
}

6. Великий дешифровщик

for (var i = 0; i < encodedMessage.length; i++) {
  if (encodedMessage[i] + shift < symbols.length) {
    decodedMessage += symbols[encodedMessage[i] + shift];
  } else {
    decodedMessage += symbols[encodedMessage[i] + shift - symbols.length];
  }
}

7. Аналитика пользователей

for (var i = 0; i < usersData.length; i++) {
  if (usersData[i].indexOf(query) >= 0 ) {
    matchingUsers++;
  }
}

8. Числа Фибоначчи

for (var i = 0; i < numbersQuantity; i++) {
  fibonacciNumbers.push
  ((fibonacciNumbers[i]) + (fibonacciNumbers[i + 1]));
}

Или:

for (var i = 2; i <= numbersQuantity + 1; i++) {
  fibonacciNumbers[i] = fibonacciNumbers[i - 1] + fibonacciNumbers[i - 2];
}

9. Быстрее, выше, сильнее

if (trainingTime <= 30) {
  levels[indicators.indexOf('скорость')] += 3;
  levels[indicators.indexOf('ловкость')] += 3;
}
if (trainingTime > 30 && trainingTime <= 60) {
  levels[indicators.indexOf('гибкость')] += 3;
}
if (trainingTime > 60) {
  levels[indicators.indexOf('сила')] += 2;
  levels[indicators.indexOf('выносливость')] += 2;
}

10. Уникальные элементы

for (var i = 0; i < numbers.length; i++) {
  var x = 0;
  for (var j = 0; j < numbers.length; j++) {
    if (i !== j) {
      if (numbers[i] === numbers[j]) {
        x = 1;
      }
    }
  }
  if (x !== 1) {
    uniqueNumbers.push(numbers[i]);
  }
}

11. Задом наперёд

for (var i = 0; i < (numbers.length - 1) / 2; i++) {
  var x = numbers[i];
  var y = numbers[numbers.length - 1 - i];
  numbers[i] = y;
  numbers[numbers.length - 1 - i] = x;
}

12. Сортировка выбором

for (var i = 0; i < numbers.length - 1; i++) {
  for (var j = i + 1; j < numbers.length ; j++) {
    if (numbers[j] < numbers[i]) {
      var swap = numbers[i];
      numbers[i] = numbers[j];
      numbers[j] = swap;
    }
  }
}

Функции

1. Велопарковка

var checkVehicle = function (x, y) {
  var z = '';
  if (x === 2 && y < 100) {
    z = 'Парковка разрешена';
  } else {
    z = 'Вам здесь не место! Мяу!';
  }
  return z;
};

2. На глубине

var calculatePressure = function (x, y) {
  var z = Math.round(x * y * 9.8);
  return z;
};

3. Калькулятор

var calculate = function (firstNumber, secondNumber, operator) {
  z = 0;
  if (operator === '+') {
    z = parseInt(firstNumber, 10) + parseInt(secondNumber, 10);
  }
  if (operator === '-') {
    z = parseInt(firstNumber, 10) - parseInt(secondNumber, 10);
  }
  if (operator === '*') {
    z = parseInt(firstNumber, 10) * parseInt(secondNumber, 10);
  }
  if (operator === '/') {
    z = parseInt(firstNumber, 10) / parseInt(secondNumber, 10);
  }
  return z;
};

4. Достаточно

var getDiet = function (x, y) {
  var z = 0;
  for (var i = 0; i < x.length; i++) {
    if (z + x[i] > y) {
      return i;
    } else {
      z += x[i];
    }
  }
};

5. Перекладывание бумажек

var getDocumentsNumbers = function (x, y) {
  var z = 0;
  for (var i = 0; i < x.length; i++) {
    if (x[i][4] + x[i][5] + x[i][6] + x[i][7] === y.toString()) {
      z += 1;
    }
  }
  return z;
};

Или:

var getDocumentsNumbers = function (x, y) {
  var z = 0;
  for (var i = 0; i < x.length; i++) {
    if (x[i].indexOf(y, 1) === 4) {
      z += 1;
    }
  }
  return z;
};

6. Как ты мне дорог

var calculateExpences = function (netSalary) {
  var gross = Math.round(netSalary / (100 - incomeTax) * 100);
  var contributionsX = Math.round(gross * contributions / 100);
  var z = gross + contributionsX;
  return z;
};

7. Олимпиада для котов

var getYears = function (x, y, z) {
  var mass = [];
  for (var i = x; i <= y; i++) {
    var summ = 0;
    for (var j = 0; j < i.toString().length; j++) {
      var h = i.toString();
      summ += parseInt(h[j], 10);
    }
    if (summ === z) {
      mass.push(i);
    }
  }
  return mass;
}

8. Какой сегодня день?

var getDayOfWeek = function (x, y) {
  var week = ['понедельник', 'вторник', 'среда', 'четверг', 'пятница', 'суббота', 'воскресенье'];
  var shift = week.indexOf(x);
  var z = 0;
  if (y > 7) {
    z = y % 7 + shift - 1;
  } else {
    z = y + shift - 1;
  }
  return week[z];
};

9. Квадратные корни

var calculateRoots = function (a, b, c) {
  var d = b * b - 4 * a * c;
  var z = '';
  if (d < 0) {
    z = 'Корней нет';
  }
  if (d === 0) {
    var x = -b / (2 * a);
    z = 'Корень равен ' + x;
  }
  if (d > 0) {
    var x = (-b + Math.sqrt(d)) / (2 * a);
    var y = (-b - Math.sqrt(d)) / (2 * a);
    z = 'Первый корень равен ' + x + ', второй корень равен ' + y;
  }
  return z;
};

10. Деньги к деньгам

var calculateDeposit = function (dep, pr, per, isK) {
  var x = 0;
  if (!isK) {
    x = (pr / 100 / 12) * per * dep;
  }
  if (isK) {
    for (var i = 1; i <= per; i++) {
      x += (pr / 100 / 12) * (dep + x)
    }
  }
  return Math.floor(x + dep);
};

11. Вечный вопрос

var calculateDeposit = function (dep, pr, per, isK) {
  var x = 0;
  if (!isK) {
    x = (pr / 100 / 12) * per * dep;
  }
  if (isK) {
    for (var i = 1; i <= per; i++) {
      x += (pr / 100 / 12) * (dep + x)
    }
  }
  return Math.floor(x + dep);
};

var getProfitableDeposit = function (dep, per, prS, prK) {
  var zz = '';
  var xx = calculateDeposit(dep, prS, per, false);
  var yy = calculateDeposit(dep, prK, per, true);
  if (xx > yy) {
    zz = 'Выбирай обычный вклад. Заработаешь ' + xx;
  } else {
    zz = 'Выбирай капитализацию. Заработаешь ' + yy;
  }
  return zz;
};

Программы курса

Первая программа: KeksoFit v0.1

var jumps = foodInGrams / 10 * 3;

var pulls = sleepInHours * 2;

var runs = jumps + pulls / 2;

Вторая программа: «Сколько гулять?»

if (!isRaining) {
  if (temperature >= 10 && temperature < 15 ) {
    minutes = 30;
  } else if (temperature >= 15 && temperature < 25 ) {
    minutes = 40;
  } else if (temperature >= 25 && temperature <= 35 ) {
    minutes = 20;
  } else {
    minutes = 0;
  }
} else {
  minutes = 0;
}

Третья программа: «Протеиновый коктейль!»

for (var i = 1; i <= days; i++) {

 if (i % 2 === 0) {
   total += evenDayAmount;
 } else {
   total += oddDayAmount;
 }

}

Четвёртая программа: «Бешеная сушка»

while (current > targetWeight) {
  current *= 0.95;
  days++;
}

Пятая программа: «Начинающий дешифровщик»

for (var i = 0; i < encodedMessage.length; i++) {
  decodedMessage += symbols[encodedMessage[i]];
}

Шестая программа: «Рекорды по прыжкам в длину»

for (var i = 0; i <= attempts.length - 2; i++) {

  var max = attempts[i];

  for (var j = i + 1; j <= attempts.length - 1; j++) {
    if (attempts[j] > max) {
      max = attempts[j];
      var swap = attempts[i];
      attempts[i] = max;
      attempts[j] = swap;
    }
  }
}

averageBest = (attempts[0] + attempts[1] + attempts[2]) / 3;

if (averageBest > qualificationDistance) {
  qualified = true;
} else {
  qualified = false;
}

Седьмая программа: «От зарплаты до зарплаты»

var calculateSalary = function (x) {
  var y = 0.35;
  if (x > 100000) {
    y = 0.45;
  }
  var z = x - Math.round(x * y);
  return z;
};

Восьмая программа: «Сколько стоит ваш фронтенд?»

var getPrice = function (t, q) {
  var fix = 1500;
  if (q) {
    t /= 2;
    fix *= 2.5;
  }
  if (t > 150) {
    fix -= 250;
  }
  return t * fix;
};

Девятая программа: «Не трать деньги понапрасну»

var getPrice = function (t, q) {
  var fix = 1500;
  if (q) {
    t /= 2;
    fix *= 2.5;
  }
  if (t > 150) {
    fix -= 250;
  }
  return t * fix;
};

var getProfitableProject = function (t, profit) {
  var x = getPrice(t, true) - profit;
  var y = getPrice(t, false);
  var z = '';

  if (x < y) {
    z = 'Выгодней срочный проект. Потратишь на него ' + x;
  } else {
    z = 'Выгодней обычный проект. Потратишь на него ' + y
  }
  return z;
};

Десятая программа: «Золотой мяч»

var getStatistics = function (players) {
  var allgoals = 0;

  for (var i = 0; i < players.length; i++) {
    allgoals += players[i].goals;
  }

  for (var i = 0; i < players.length; i++) {
    players[i].coefficient = players[i].goals * 2 + players[i].passes;
    players[i].percent = Math.round(players[i].goals / allgoals * 100);
  }

  return players;
};

Одиннадцатая программа: «Дом, который построил Кекс»

var house = {
  rooms: 10,
  floors: 5,
  material: 'wood',
  coefficient: 10.5,

  calculateSquare: function () {
    return this.rooms * this.coefficient * this.floors;
  },

  calculatePrice: function () {
    return this.calculateSquare() * materialPrice[this.material];
  }
};

Двенадцатая программа: «Испытание мороженым»

var updateCards = function (data) {
  var products = document.querySelectorAll('.good');
  for (var i = 0; i < products.length; i++) {
    var product = products[i];
    var element = data[i];

    var stock = 'good--available';
    if (!element.inStock) {
      stock = 'good--unavailable';
    }
    product.classList.add(stock);

    if (element.isHit) {
      product.classList.add('good--hit');
    }
  }
};

updateCards(assortmentData);

Тринадцатая программа: «Мороженое. Возвращение»

var makeElement = function (tagName, className, text) {
  var element = document.createElement(tagName);
  element.classList.add(className);
  if (text) {
    element.textContent = text;
  }
  return element;
};

var renderCards = function (product) {
  var listItem = makeElement('li', 'good');

  var title = makeElement('h2', 'good__description', product.text);
  listItem.appendChild(title);

  var picture = makeElement('img', 'good__image');
  picture.src = product.imgUrl;
  picture.alt = product.text;
  listItem.appendChild(picture);

  var price = makeElement('p', 'good__price', product.price + '₽/кг');
  listItem.appendChild(price);

  var availabilityClass = 'good--available';
  if (!product.inStock) {
    availabilityClass = 'good--unavailable';
  }
  listItem.classList.add(availabilityClass);

  if (product.isHit) {
    listItem.classList.add('good--hit');
  }

  if (product.specialOffer) {
    var specialPrice = makeElement('p', 'good__special-offer', product.specialOffer);
    listItem.appendChild(specialPrice);
  }

  return listItem;
};

var cardList = document.querySelector('.goods');

for (var i = 0; i < cardsData.length; i++) {
  var cardItem = renderCards(cardsData[i]);
  cardList.appendChild(cardItem);
}