Coder Social home page Coder Social logo

jspace's Introduction

JSpace

image alt text

https://qweb.by

Alexander Konkov

[email protected]
https://www.facebook.com/sander.konkov
https://t.me/sk_ax
https://github.com/SkyAx

2016 - 2019

Источники

Содержание

**1. ****Знакомство с HTML5, Doctyp**e

  1. **Прошлое и будущее HTM**L

  2. История языка HTML**5 **

  3. **Три основных принципа HTML**5

  4. **Выбор редактора, создание страниц**ы

**2. ****Знакомство с CSS и CSS**3

  1. **Внутренние или внешние таблицы стилей**?

  2. **Создаем свой первый CSS файл. Знакомство с синтаксисо**м

**3. ****Знакомство с Bootstra**p

  1. Преимущества Bootstra**p **

  2. **Bootstrap и его аналоги. Сравнение фреймворко**в

**4. ****Знакомство с LES**S

  1. Почему** LES**S**?**** **

  2. **LESS и его аналог**и

**

****5. ****Знакомств**о JavaScrip**t **

  1. Что умеет JavaScript**? **

  2. Что не умеет JavaScript**? **

  3. В чем уникальность JavaScript**? **

  4. Типы данных в JavaScrip**t **

  5. **Основные оператор**ы

  6. Основные оператор**ы **

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

  8. Взаимодействие с пользователем: alert(), confirm(), prompt(**) **

  9. Логические операторы ||(или), &&(и), !(не**) **

  10. ** **Преобразование типов для примитиво**в **

  11. Циклы while / for** **

  12. Конструкция switc**h **

  13. Функци**и **

  14. Функциональные выражени**я **

  15. Все вместе : Особенности JavaSсrip**t **

**6. ****Структуры данных в JavaScrip**t

  1. Введение в методы и свойств**а **

  2. Числ**а **

  3. Строк**и **

  4. Объекты как ассоциативные массив**ы **

  5. Объекты : перебор свойст**в **

  6. Объекты : передача по ссылк**е **

  7. Массивы с числовыми индексам**и **

  8. Псевдомассив аргументов "argument**s**"** **

  9. Дата и Врем**я

**

**7. ****Замыкания, область видимост**и

  1. Глобальный объек**т **

  2. Замыкания, функции изнутр**и **

  3. Ключевое слово thi**s **

  4. **Bind, call, appl**y

**8. BOM, DOM **

  1. Объектная модель документ**а **

  2. Объектная модель браузер**а **

  3. Дерево DO**M **

  4. Навигация по DOM-элемента**м **

  5. Поиск: getElement*, querySelector*, други**е


**

9. Асинхронное программирование в JS

  1. setTimeout, setInterva**l **

  2. AJA**X **

  3. **Основы XMLHttpReques**t

** **

Приложение** **

** ****1. **Введение в библиотеку jQuer**y **

  1. История создания и описание библиотек**и **

  2. Подключение библиотек**и **

  3. Основы jQuer**y **

**9. **Углубленный jQuer**y **

  1. Установка и чтение атрибутов элемент**а **

  2. События на страниц. Создание интерактивных страни**ц **

  3. **Использование событи**й

**2. ****Знакомство с Bowe**r

**3. ****Знакомство с** **Gulp **

  1. Gulp таск**и **

  2. **Добавление Gulp плагино**в

**4. Обзор протокола HTTP **

  1. Составляющие систем, основанных на HTT**P **

  2. Клиент: участник обмен**а **

  3. Веб-серве**р **

  4. Прокс**и **

  5. HTTP сообщени**я **

  6. **Итог**о

Знакомство с HTML5, Doctype

image alt text

Прошлое и будущее HTML

HTML (от англ. HyperText Markup Language — «язык гипертекстовой разметки») — стандартизированный язык разметки документов во Всемирной паутине.

Язык HTML был разработан британским учёным Тимом Бернерсом-Ли приблизительно в 19861991 годах в стенах ЦЕРНа в Женеве в Швейцарии. HTML создавался как язык для обмена научной и технической документацией, пригодный для использования людьми, не являющимися специалистами в области вёрстки. HTML успешно справлялся с проблемой сложности SGML путём определения небольшого набора структурных и семантических элементов — дескрипторов. Дескрипторы также часто называют «тегами». С помощью HTML можно легко создать относительно простой, но красиво оформленный документ. Помимо упрощения структуры документа, в HTML внесена поддержка гипертекста. Мультимедийные возможности были добавлены позже.

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

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

… Читать далее на wikipedia

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

Организация W3C (World Wide Web Consortium, Консорциум Всемирной паутины) которая занимается разработкой и внедрением официальных стандартов Всемирной паутины, забросила язык HTML в далеком 1998 г., считая его неспособным на дальнейшее выживание. Свои надежды на будущее консорциум W3C возлагал на модернизированного наследника HTML — язык XHTML. Но язык HTML не умер. Его "подобрала" группа программистов-аутсайдеров и не только возвратила его к жизни, но и заложила основу для новых возможностей, которые мы с вами и исследуем в на протяжении курса. На этом занятии мы выясним, почему язык HTML был брошен умирать от старости и как он был возвращен к жизни. Мы узнаем основные принципы и возможности языка HTML5, а также рассмотрим проблему поддержки этого языка разными браузерами. Кроме этого, мы также рассмотрим настоящий документ HTML5, как его самую простую форму, так и более практический шаблон, который можно использовать в качестве отправной точки для создания любого веб-сайта.

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

История языка HTML5

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

Очень стары е веб-страницы без проблем обрабатываются в наиболее современных браузерах (включая и те, которые не существовали на момент создания этих страниц, например Firefox или Chrome).

Но успех и почтенный возраст также несут с собой определенные существенные угрозы. Что и случилось с языком HTML — в 1988 г. консорциум W3C прекратил его поддержку и попытался заменить его языком на основе языка XML - XHTML 1.0 вышедшем в 2000 году.

На смену HTML в 2000 году пришла спецификация XHTML 1.0. Буква «X» здесь означает XML.

XML (от англ. eXtensible Markup Language — расширяемый язык разметки, компактное упрощенное подмножество языка SGML) — рекомендованный W3C язык разметки, представляющий собой свод общих правил, нацеленных на создание описаний данных.

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

XHTML — это попытка обеспечить описания данных с помощью выразительных средств сложного XML, сохранив при этом простоту и удобство HTML.

Приблизительно в то же самое время (начиная с 2004 г.) группа разработчиков начала рассматривать будущее Всемирной паутины в другом ракурсе. Вместо того чтобы попытаться разобраться, что было неправильным (или просто "грязным" с философской точки зрения) в HTML, они сфокусировались на том, чего в нем не хватало, что хотели бы иметь веб-разработчики для воплощения своих идей. В конце концов, HTML зародился как инструмент для отображения документов. С добавлением языка сценариев JavaScript HTML преобразовался в систему для разработки веб-приложений, таких как поисковые движки, онлайновые магазины, картографические инструменты, средства чтения электронной почты и многие другие. Но в то время как искусное веб-приложение может делать много чего впечатляющего, создать такое приложение — задача не из легких. Большинство разработчиков использует для этого мешанину кода JavaScript, один или несколько популярных инструментариев JavaScript, а также веб-приложение, исполняемое на веб-сервере. Добиться правильного и единообразного взаимодействия всех этих составляющих на разных браузерах — сложная задача. Даже когда все наконец работает, нужно постоянно "присматривать за скотчем и скобами", которые удерживают всю конструкцию.

Такая ситуация вызывала особенную озабоченность среди разработчиков браузеров, поэтому группа дальновидных разработчиков из компании Opera Software (создатели браузера Opera) и компании Mozilla Foundation (создатели браузера Firefox) начали агитировать за включение в XHTML больше возможностей, ориентированных на разработчиков. Когда их попытки не увенчались успехом, компании Opera, Mozilla и Apple создали группу WHATWG (Web Hypertext Application Technology Working Group, рабочая группа по технологии гипертекстовых веб-приложений) с целью работы над новыми решениями.

Группа не ставила перед собой задачу заменить HTML, ее целью было плавное расширение языка, и причем такое, чтобы расширения были обратно совместимыми. Надо сказать, что самая ранняя версия работы этой группы включала две спецификации расширений — Web Applications 1.0 и Web Forms 2.0. В конечном итоге эти стандарты эволюционировали в HTML5. В двухтысячных годах все интересное происходило в лагере группы WHATWG. После некоторого периода болезненных размышлений организация W3C решила распустить работающую над XHTML 2 группу и работать вместо этого над формализацией стандарта HTML5. На этом этапе первоначальный стандарт HTML5 был разделен на более управляемые части, и многие из его функциональных возможностей стали отдельными стандартами.

Ознакомиться с официальной версией стандарта HTML5 организации W3C можно на

веб-сайте по адресу: www.w3.org/TR/html5

HTML5 (англ. HyperText Markup Language, version 5) — язык для структурирования и представления содержимого всемирной паутины. Это пятая версия HTML. Хотя стандарт был завершён (рекомендованная версия к использованию) только в 2014 году[1][2] (предыдущая, четвёртая, версия опубликована в 1999 году[3]), ещё с 2013 года[4] браузерами оперативно осуществлялась поддержка, а разработчиками — использование рабочего стандарта (англ. HTML Living Standard). Цель разработки HTML5 — улучшение уровня поддержки мультимедиа-технологий с одновременным сохранением обратной совместимости, удобочитаемости кода для человека и простоты анализа для парсеров

… Читать далее на wikipedia

Три основных принципа HTML5

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

Не рви Паутину

Требование "Не рвать Паутину" означает, что стандарт не должен вносить изменения, которые сделают нерабочими веб-страницы других разработчиков. Но такое случается редко. "Не рвать Паутину" также означает, что стандарт не должен мимоходом изменять правила и считать устаревшими совершенно нормальные современные веб-страницы (если они продолжают работать). Например, XHTML 2 порвал Паутину, т. к. требовал немедленно коренным образом изменить подход к написанию веб-страниц. Да, благодаря встроенной в браузеры поддержке обратной совместимости старые страницы продолжали бы работать. Но чтобы подготовиться к будущему и поддерживать свою веб-страницу, разработчикам потребовалось бы затратить множество часов, исправляя запрещенные в XHTML 2 "ошибки". В HTML5 совсем другая философия. Все, что было правильным до HTML5, остается правильным и в HTML5.

Асфальтируйте** тропинки**

Тропинка представляет собой неровный, протоптанный путь, позволяющий людям добраться из одной точки в другую. Тропинки существуют, т. к. они используются. Тропинка может быть не лучшим путем, но на определенном этапе она является самым практическим работающим решением.Стандарт HTML5 задается целью стандартизировать эти неофициальные, но широко применяемые, методы. Возможно, результат этого подхода не будет таким аккуратным, как прокладка новой заасфальтированной дороги с применением последних технологий, но у него больше шансов на успех. Причина кроется в том обстоятельстве, что переход к использованию новых методов может оказаться не под силу или не представлять интереса для веб-разработчика среднего уровня. Что еще хуже, новые методы могут не работать в старых браузерах, которыми пользуются посетители веб-страницы. Стандарт XHTML 2 пытался заставить людей не пользоваться тропинками, но потерпел в этом предприятии сокрушающее поражение.

Будьте практичными

Это простой принцип: все изменения должны служить практической цели. И чем более трудоемкое изменение, тем большей должна быть ожидаемая от нее отдача. Веб-разработчикам могут быть больше по душе тщательно разработанные, единообразные стандарты без странностей, но это недостаточно веская причина, чтобы менять язык, на котором уже создано несколько миллиардов документов. Конечно же, кто-то должен еще решить, чьи интересы являются более важными. Для решения этого вопроса хорошо бы посмотреть, что веб-страницы уже делают или пытаются делать.

Например, третьим самым популярным веб-сайтом в мире был сайт YouTube. Но так как до HTML5 в HTML не было настоящих возможностей поддержки видео, то в своей работе создателям этого сайта пришлось использовать подключаемый к браузеру Flash-модуль. Это решение работает на удивление хорошо, т. к. такой Flash-модуль установлен, как правило, на всех подключенных к Интернету компьютерах. Но иногда случаются исключения из этого правила: на корпоративных компьютерах может быть запрещена установка Flash-модуля, а устройства Apple (такие как iPhone или iPad) вообще не поддерживают его. И несмотря на то, на скольких компьютерах может быть установлен Flash-модуль, есть хорошее основание для расширения стандарта HTML, чтобы он поддерживал напрямую одно из самых распространенных применений веб-страниц — просмотр видео.

Подобным образом мотивируется стремление добавить к HTML5 дополнительную поддержку метода "перетащить и бросить" для интерактивных элементов, редактируемого HTML-содержимого, рисования на двумерном холсте и т. п. Не нужно далеко ходить, чтобы найти веб-страницы, в которых все эти возможности применяются уже сейчас. В одних это делается с помощью подключаемых модулей типа Adobe Flash или Microsoft Silverlight, а в других — с помощью библиотек JavaScript или (что более трудоемко) посредством специально созданных страниц JavaScript.

Почему же тогда не добавить в стандарт HTML официальную поддержку этих возможностей и не обеспечить их единообразную работу на всех браузерах?

Выбор редактора, создание страницы

WebStorm Brackets Sublime Text 3 Atom
IDE - Интегрированная среда разработки (англ. Integrated Development Environment) Текстовый редактор с возможностью расширения функционала с помощью плагинов. Текстовый редактор с возможностью расширения функционала с помощью плагинов. Текстовый редактор с возможностью расширения функционала с помощью плагинов.

Устанавливаются как любые программы, кроссплатформенные, большое комьюнити, множество плагинов.

В своей работе я использую WebStorm - мощная, удобная, расширяемая, кроссплатформенная IDE.

Для быстрого редактирования файлов, я использую Atom. Он быстро стартует, имеет некоторые функции IDE, вполне подходит как основной редактор, но чаще используется как инструмент для быстрого редактирования или "заглядывания" в код.

Подробнее с редакторами можно ознакомиться через официальные сайты или на YouTube.

Давайте создадим первый HTML-документ:

  1. Выберем Файл-Создать и создадим файл index.html.

image alt text

Далее мы начнем заполнять документ(страницу), согласно общепринятым правилам. Первым делом мы объявим doctype в стиле HTML5, сделаем стандартную HTML5 страницу.

image alt text

Давайте разберемся с парными и непарными тегами. Теги , обрамляющие какой либо контент, парные - p, span, div, section, body Теги, с указаниями настроек HTML документа, для оформления текста, вставки картинок или полей ввода - одинарные. Они не подходят на роль обрамляющих контент элементы, но играют самостоятельную и такую же важную роль в формировании веб-страниц. Дополним нашу страницу информацией, применив оба вида тегов.

image alt text

Сохраните изменения, и откройте файл index.html в папке Урок1 и запустите его в любом браузере. Поздравляю , это ваш первый html-документ / веб-страница.

image alt text

Несколько слов о путях к файлам в документе.

Часто используемые для этого атрибуты и свойства в CSS это : src, url, href

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

Пути бывают

  1. Относительные: src="images/images.png” или же если бы картинка была бы не в папке, то src=”images.png”, если бы уровнем ниже, то src=”../images.png”

  2. Абсолютные : src="http://static33.cmtt.ru/paper-media/fd/92/e5/0479e08f8e852d.png

Знакомство с CSS и CSS3

image alt text

CSS (/siːɛsɛs/ англ. Cascading Style Sheetsкаскадные таблицы стилей) — формальный язык описания внешнего вида документа, написанного с использованием языка разметки.

Преимущественно используется как средство описания, оформления внешнего вида веб-страниц, написанных с помощью языков разметки HTML и XHTML, но может также применяться к любым XML-документам, например, к SVG или XUL.

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

...Читать дальше на wikipedia

Каскадные таблицы стилей, или Cascading Style Sheets (CSS), обеспечивают творческую свободу в разметке и дизайне веб-страниц. Пользуясь CSS, вы сможете украсить текст страниц привлекательными заголовками, буквицами и рамками,как в красочных глянцевых журналах. Можно точно разместить и позиционировать изображения, сделать колонки и создать баннеры, выделить ссылки динамическими эффектами. Можно также добиться постепенного появления и исчезновения элементов, перемещения объектов по странице или медленного изменения цвета кнопки при прохождении над ней указателя мыши.

Вы думаете, что все это довольно сложно? Напротив! Каскадные таблицы стилей как раз и предназначены для упрощения процесса оформления веб-страниц.

Каскадные таблицы стилей работают с HTML-кодом, но не имеют никакого отношения к языку HTML. Это совершенно другой язык. HTML структурирует документ, упорядочивая информацию в заголовки, абзацы, маркированные списки и т. д., в то время как CSS тесно взаимодействует с браузером, чтобы оформление HTML-документа имело совершенный вид.

Например, вы могли бы использовать HTML, чтобы превратить фразу в заголовок, отделяя его от содержимого страницы, но лучше использовать CSS для форматирования заголовка, скажем, крупным полужирным красным шрифтом с позиционированием на 50 пикселов от левого края окна. В CSS это форматирование текста включает в себя стиль — правило, описывающее внешний вид конкретной части веб-страницы. А таблица стилей является набором таких стилей.

Можно также создавать стили специально для работы с изображениями. На-

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

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

и других элементов страницы. Например, вы можете создать стиль и применить

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

Создав стиль один раз, можно применять его к текстовым фрагментам, изобра-

жениям, заголовкам и любым другим элементам страницы сколько угодно раз. Например, вы можете выбрать абзац текста и применить к нему стиль, тут же изменя­ющий размер, цвет и шрифт текста. Можно также создать стили для определенных HTML-элементов так, чтобы, например, все заголовки первого уровня (элементы h1 ) на вашем сайте были отображены в одинаковом стиле независимо от того, где они размещены.

Определение стиля в CSS, устанавливающего внешний вид какого-либо элемента (фрагмента) веб-страницы, — это всего лишь правило, которое сообщает браузеру, что и каким образом форматировать: изменить цвет шрифта заголовка на синий, выделить фото красной рамкой, создать меню шириной 150 пикселов для списка гиперссылок. Если бы стиль мог говорить, он сказал бы: «Браузер, сделай, чтобы вот это выглядело так-то».

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

элемента веб-страницы, который непосредственно подлежит форматированию

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

Например, тело сайта, включает простой стиль:

body {

font-family: "Franklin-Book", Helvetica, Arial, sans-serif;

color: #222;

}

Разумеется, CSS-стили не могут быть написаны на обычном языке, как, напри-

мер, предыдущий абзац. У них есть собственный язык. В частности, чтобы установить красный цвет и размер шрифта 1,5 em для всех абзацев на веб-странице, нужно написать следующее:

p { color: red; font-size: 1.5em; }

Внутренние или внешние таблицы стилей?

Таблицы стилей бывают двух видов — внутренние и внешние — в зависимости от того, где определена информация о стилях: непосредственно в самой веб-странице или в отдельном файле, связанном с веб-страницей.

Еще с момента изобретения CSS внешние таблицы стилей были лучшим способом создания дизайна веб-страниц.

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

Внешние таблицы стилей позволяют веб-страницам загружаться быстрее.

Когда вы используете такие таблицы стилей, веб-страницы содержат только

HTML-код, без кода громоздких вложенных таблиц для форматирования, без

элементов font и подобных, без кода внутренних каскадных таблиц стилей. Кроме того, когда браузер загрузит внешнюю таблицу стилей, он сохранит ee на клиентском компьютере посетителя веб-страницы (в специальной си­стемной папке, называемой кэшем) для быстрого доступа к нему. Когда посетитель веб-страницы переходит к другим страницам сайта, которые используют

ту же внешнюю таблицу стилей, браузеру нет необходимости снова загружать.

таблицу стилей. Он попросту загружает запрашиваемый HTML-файл и использует внешнюю таблицу стилей из своего кэша, что дает существенный выигрыш во времени загрузки страниц.Внутренняя таблица стилей — это набор стилей, являющийся частью кода веб-страницы, которая всегда должна находиться между открывающим и закрыва­ющим тегами <style> и </style> HTML-кода в теле веб-страницы, то есть внутри элемента head .

<style> h1 { color: #FF7643; font-family: Arial; } p { color: red; font-size: 1.5em; } </style>

Внешняя таблица стилей — это не что иное, как текстовый файл, содержащий

весь набор стилей CSS. Он не должен включать в себя HTML-код, поэтому никогда не добавляйте в файл внешней таблицы стиля элемент style . Вдобавок имя этого файла всегда должно заканчиваться расширением CSS. Можно присвоить какое угодно имя этому файлу, но лучше, чтобы оно было информативным. Назовите файл внешней таблицы стилей, например, global.css , main.css или просто styles.css , если это общая таблица стилей, связанная со всеми страницами вашего сайта, или form.css , если он содержит код для форматирования веб-форм сайта.

Создав внешнюю таблицу стилей, вы должны подключить ее к форматируемой

веб-странице. Это можно сделать с помощью HTML-элемента link :

Элемент link обладает двумя атрибутами:

  1. rel="stylesheet" — указывает тип ссылки; в данном случае это ссылка на таблицу стилей;

  2. href — определяет местонахождение внешнего CSS-файла на сайте.

Значение этого атрибута — URL-адрес, который будет отличаться в зависимости от того, где расположен CSS-файл. Он работает так же, как атрибут src при добавлении изображения на страницу или атрибут href гиперссылки, указывающей на другую веб-страницу.

Создаем свой первый CSS файл. Знакомство с синтаксисом.

Выберем Файл-Создать и создадим файл main.css

image alt text

И подключаем его к нашей странице :

image alt text

Попробуем CSS стили в работе. Начнем с изменения цвета фона нашему основному тегу body. Свойство выглядит так:

body{

background-color: #dadada;

}

Задает белый фон странице. Первая часть - свойства, вторая - значение. В нашем случае #dadada обозначает светло-серый цвет в 16-тиричной системе. Добавим еще несколько стилей . Первый для выравнивания содержимого по центру, второй для стилизации текста и его цвета.

body{

background-color: #dadada;

** text-align: center;**

** font-family: "Helvetica", "Tahoma", sans-serif;**

** font-size: 16px;**

** color: #222;**

}

Теперь поработаем с остальными элементами в нашем index.html и применим новые стили к ним .

/Стили для картинки/

img{

width: 250px;

display: block;

margin: 0 auto;

}

h1{

color: #656565;

border: 3px solid #222;

/*padding: 10px;*/

/*border-bottom: 3px solid #222;*/

/*padding-bottom: 10px;*/

/*border-bottom: 3px solid #222;*/

/*display: inline-block;*/

}

Обновите и посмотрите что получилось. Теперь "раскомментируйте" по очереди стили заголовка первого уровня. Посмотрите изменения , происходящие с заголовком h1.

Теперь добавьте ниже следующие стили для параграфа текста

p{

text-align: left;

font-family: serif;

width: 600px;

font-size: 20px;

line-height: 1.6;

margin: 0 auto;

border-bottom: 3px solid #222;

}

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

image alt text

Bootstrap (также известен как Twitter Bootstrap[3][4][5]) — свободный набор инструментов для создания сайтов и веб-приложений. Включает в себя HTML- и CSS-шаблоны оформления для типографики, веб-форм, кнопок, меток, блоков навигации и прочих компонентов веб-интерфейса, включая JavaScript-расширения.

Bootstrap использует самые современные наработки в области CSS и HTML, поэтому необходимо быть внимательным при поддержке старых браузеров[6]. ...Читать дальше на wikipedia

Создан в застенках компании Twitter, сначала использовался для собственных продуктов и назывался "Twitter Bootstrap", а позже был выпущен на волю. За это у него забрали слово Twitter из названия.

Bootstrap — это CSS/HTML фреймворк для создания сайтов. Другими словами, это набор инструментов для вёрстки. В нём есть ряд преимуществ, благодаря которым BS считается самым популярным из себе подобных. Bootstrap работает с препроцессорами LESS и SASS

Преимущества Bootstrap

Вот основные преимущества, которые дает Bootstrap, при работе с ним.

  1. Скорость работы — благодаря множеству готовых элементов верстка с бутстрапом занимает значительно меньше времени;

  2. Масштабируемость — добавление новых элементов не нарушает общую структуру;

  3. Легкая настраиваемость — редактирование стилей производится путём создания новых css-правил, которые исполняются вместо стандартных. При этом не требуется использовать атрибуты типа "!important";

  4. Большое количество шаблонов — о шаблонах Bootstrap я напишу далее;

  5. Огромное сообщество разработчиков;

  6. Широкая сфера применения — Bootstrap используется в создании тем для практически любой CMS, в разработке сложных веб-приложений и SPA.

Ознакомится с фреймворком можно на официальном сайте http://getbootstrap.com/ и на русскоязычном портале http://mybootstrap.ru/

Bootstrap и его аналоги. Сравнение фреймворков.

Foundation

image alt text

Создатели: ZURB

Год выхода: 2011

Текущая версия: 5.4.7

Популярность: 24,600+ звезды на GitHub

**Размер: **326 KB

Препроцессоры: Sass

**Адаптивность: **Да

Модульность: Да

Базовые шаблоны / макеты: Да

**Набор иконок: **Foundation Icon Fonts

Расширения / Дополнения: Да

Документация: Хорошая

Кастомизация: Нет, только ручная настройка.

Поддержка браузеров: Chrome, Firefox, Safari, IE9 +; IOS, Android, Windows Phone 7 +

Лицензия: MIT

Semantic UI

image alt text

Автор: Jack Lukic

**Год выхода: **2013

Текущая версия: 1.2.0

Популярность: 31,000+ звезд на GitHub

Размер: 552 KB

Препроцессоры: Less

Адаптивность: Да

Модульность: Да

Базовые шаблоны / макеты: Нет

Набор иконок: Font Awesome

Расширения / Дополнения: Нет

Документация: Очень хорошая

Кастомизация: Нет, только ручная настройка.

Поддержка браузеров: Firefox, Chrome, Safari, Internet Explorer 10 + (IE9 с браузера префикса только), Android 4, Blackberry 10

Лицензия: MIT

Bootstrap

image alt text

**Создатели: **Mark Otto и Jacob Thornton

**Год выхода: **2011

**Текущая версия: **3.3.7 , 4.0.0 (alpha)

Популярность: 104,000+ звезды на GitHub

**Размер: **145 KB

**Препроцессоры: **Less и Sass

Адаптивность: Да

Модульность: Да

**Базовые шаблоны / макеты: **Да

Набор иконок: Glyphicons Halflings набор

Расширения / Дополнения: Нет в комплекте, но многие сторонние плагины доступны.

Документация: Хорошая

**Кастомизация: **Есть. К сожалению, вам нужно ввести значения цвета вручную, поскольку нет возможности выбора цвета.

**Поддержка браузеров: **Firefox, Chrome, Safari, IE8 + (необходимо Respond.js для IE8)

Лицензия: MIT

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

Другие : http://getskeleton.com/

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

image alt text

LESS — это динамический язык стилей, который разработал Alexis Sellier. Он создан под влиянием языка стилей Sass, и, в свою очередь, оказал влияние на его новый синтаксис «SCSS», в котором также использован синтаксис, являющийся расширением СSS[1].

LESS — это продукт с открытым исходным кодом. Его первая версия была написана на Ruby, однако в последующих версиях было решено отказаться от использования этого языка программирования в пользу JavaScript. Less — это вложенный метаязык: валидный CSS будет валидной LESS - программой с аналогичной семантикой.

LESS обеспечивает следующие расширения CSS: переменные, вложенные блоки, миксины, операторы и функции[2].

LESS может работать на стороне клиента (Internet Explorer 6+, WebKit, Firefox) или на стороне сервера под управлением Node.js или Rhino[2].

… читать дальше на wiki

LESS — это препроцессор CSS. Это означает, что сначала вы пишете LESS-код, который затем компилируется в CSS-код для браузера. Вы можете воспринимать метаязык Less как нечто вроде сокращенного варианта записи CSS-кода, который позволяет писать код меньшего объема.

Метаязык LESS работает с файлами двух типов: LESS-файлы, которые имеют расширение .less, и CSS-файлы, имена которых (как вы знаете) оканчиваются

символами .css. На самом деле вы редактируете только файлы .less. Препроцессор Less автоматически преобразует (компилирует) LESS-файл в привычный файл .css. Может показаться, что для того, чтобы создать CSS-код, о котором вы узнали в этой книге, необходимо проделать дополнительную работу. Однако, поскольку ваши сайты и их таблицы стилей станут больше и сложнее, LESS вносит ряд преимуществ.

  • Он организует ваш CSS-код в файлы меньшего размера.

  • Вам понадобится писать меньше кода. LESS содержит некоторые действительно мощные инструменты, которые позволяют писать меньше кода. Помните вендорные префиксы?

  • У LESS есть много других преимуществ, с которыми вы познакомитесь по мере знакомства с ним, но суть в том, что данный метаязык повысит вашу эффективность в качестве Front-end разработчика: вы сможете работать быстрее и тратить больше времени на обдумывание дизайна вместо верстки кода.

Почему LESS?

Один из создателей Bootstrap опубликовал об этом короткий пост в своем блоге. Вот его основные мысли:

  1. Bootstrap компилируется c LESS в 6 раз быстрее, чем с Sass

  2. Less написан на JavaScript, что намного проще, в сравнении с Ruby, написанном на Sass.

  3. Less — это нечто большее; мы хотим чувствовать, что сами пишем CSS и настраиваем в Bootstrap абсолютно все возможности.

LESS и его аналоги

http://lesscss.org/ http://sass-lang.com/ http://stylus-lang.com/
Javascript Ruby JavaScript

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

image alt text

JavaScriptпрототипно-ориентированный сценарный язык программирования. Является реализацией языка ECMAScript (стандарт ECMA-262[8]).

JavaScript обычно используется как встраиваемый язык для программного доступа к объектам приложений. Наиболее широкое применение находит в браузерах как язык сценариев для придания интерактивности веб-страницам[9].

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

На JavaScript оказали влияние многие языки, при разработке была цель сделать язык похожим на Java, но при этом легким для использования непрограммистами. Языком JavaScript не владеет какая-либо компания или организация, что отличает его от ряда языков программирования, используемых в веб-разработке[~ 1][10].

Название «JavaScript» является зарегистрированным товарным знаком компании Oracle Corporation[11].

… читать далее на wiki

JavaScript изначально создавался для того, чтобы сделать web-странички «живыми».

Если верить википедии, языка JavaScript появился в 1995 году. Первым названием языка было LiveScript, но из-за большой популярности в то время языка Java, язык LiveScript переименовали в JavaScript. Программы на этом языке называются скриптами. В браузере они подключаются напрямую к HTML (с помощью тега <script>) и, как только загружается страничка – тут же выполняются.

JavaScript отвечает за поведение. Если HTML - это скелет, CSS - оформление, то JS - это мозги. Такая вот простая аналогия.

Как говорилось выше, JS - язык программирования. Не стоит путать и называть HTML и CSS языками программирования тоже. HTML - язык разметки. Мы размечаем тегами содержимое, определяем при этом семантику - выделяем содержимое по смыслу. CSS - это каскадные таблицы стилей. Ключевое слово здесь - таблицы. Что такое таблицы? Это сгруппированные правила. В итоге CSS это тоже не язык программирования, а правила оформления страницы, которые применяются к тегам, классам, айди и т.д.

Хорошо, JS, язык программирования, но в чем особенности этого класса ?

Для начала давайте узнаем особенности JS над другими языками :

  1. Язык JavaScript - интерпретируемый. Интерпретатор - это программа, выполняющая интерпретацию (трансляцию).

Компиляция и интерпретация, для программистов

  • Компиляция – это когда исходный код программы, при помощи специального инструмента, другой программы, которая называется «компилятор», преобразуется в другой язык, как правило – в машинный код. Этот машинный код затем распространяется и запускается. При этом исходный код программы остаётся у разработчика.

  • Интерпретация – это когда исходный код программы получает другой инструмент, который называют «интерпретатор», и выполняет его «как есть». При этом распространяется именно сам исходный код (скрипт). Этот подход применяется в браузерах для JavaScript.*

*Современные интерпретаторы перед выполнением преобразуют JavaScript в машинный код или близко к нему, оптимизируют, а уже затем выполняют. И даже во время выполнения стараются оптимизировать. Поэтому JavaScript работает очень быстро.

Чтобы было еще более понятно, чем отличаются компилируемые языки , от интерпретируемых можно рассмотреть аналогию с переводчиками. Интерпретатор - синхронный переводчик. Он переводит все "на лету", синхронно. Не записывая и не фиксируя. А компилятор - берет у вас текст для перевода, переводит и набирает переведенный текст. А потом отдает вам готовый переведенный и распечатанный текст.

  1. Язык JavaScript - динамический, т.е не строго типизированный. В переменных языках JavaScript может хранится любое значение.

Для того чтобы было проще понять что такое переменная , представьте себе коробку. В коробку можно что то положить, достать. В случае со строго типизированными языками, есть разного вида коробки и в них можно положить значения только подходящего типа, а в случае с динамическими - все что угодно. Переменная в JS может хранить в себе как цифры, так и буквы, даже слова и объекты ( тут было бы правильнее сказать ссылки, но об этом позже)*

  1. Язык JavaScript - объектно-ориентированный. Но в тоже время и функциональный. Философия объектно-ориентированных языков программирования звучит примерно так - все есть объект. Из "пакета" JavaScript предоставляет нам возможность создавать объекты - сущности с характеристиками (переменными) и поведением (функциями). В то же время язык JavaScript может быть и функциональным - это методология, при которой на первый план ставится вычисления и их последовательность или изменение состояния. При этом мы не создаем сущности.

На этом этапе нам достаточно знать эти три особенности.

Что умеет JavaScript ?

Современный JavaScript – это «безопасный» язык программирования общего назначения. Он не предоставляет низкоуровневых средств работы с памятью, процессором, так как изначально был ориентирован на браузеры, в которых это не требуется.

Что же касается остальных возможностей – они зависят от окружения, в котором запущен JavaScript. В браузере JavaScript умеет делать всё, что относится к манипуляции со страницей, взаимодействию с посетителем и, в какой-то мере, с сервером:

  1. Создавать новые HTML-теги, удалять существующие, менять стили элементов, прятать, показывать элементы и т.п.

  2. Реагировать на действия посетителя, обрабатывать клики мыши, перемещения курсора, нажатия на клавиатуру и т.п.

  3. Посылать запросы на сервер и загружать данные без перезагрузки страницы (эта технология называется "AJAX").

  4. Получать и устанавливать cookie, запрашивать данные, выводить сообщения…

  5. …и многое, многое другое!

Что не умеет JavaScript?

JavaScript – быстрый и мощный язык, но браузер накладывает на его исполнение некоторые ограничения…

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

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

Большинство возможностей JavaScript в браузере ограничено текущим окном и страницей.

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

Современные браузеры могут работать с файлами, но эта возможность ограничена специально выделенной директорией – «песочницей». Возможности по доступу к устройствам также прорабатываются в современных стандартах и частично доступны в некоторых браузерах.

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

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

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

В чём уникальность JavaScript?

Есть как минимум три замечательных особенности JavaScript:

  1. Полная интеграция с HTML/CSS

  2. Простые вещи делаются просто

  3. Поддерживается всеми распространенными браузерами и включён по умолчанию

Этих трёх вещей одновременно нет больше ни в одной браузерной технологии.

Поэтому JavaScript и является самым распространённым средством создания браузерных интерфейсов.

Типы данных в JavaScript

В языке JavaScript есть семь типов данных. Делятся они на основные, составные и специальные.

Число (основной тип данных)

Тип данных число используется для целых чисел и для дробных

let num = 12; // целое число

let num = 12.345; // дробное число

Существуют специальные числовые значения такие как Infinity и NaN.

Например, бесконечность Infinity получается при делении на ноль, а NaN - при некорректном математическом вычислении (Например console.log(‘не число’ / 2 ); // NaN ).

Строка (основной тип данных)

let language = 'JavaScript';

К типу данных "Строка" мы еще вернемся и подчеркнем его особенности перед другими типами данных.

Булевый (основной тип данных)

Как правило данный тип используется для хранения логического "да” или "нет” (истина / ложь )

let isJavaScript = true;

let isCPlusPlus = false;

**Символ (основной тип данных) ***

Новый примитивный тип данных Symbol служит для создания уникальных идентификаторов.

let symbol = Symbol();

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

let isAdmin = Symbol("isAdmin");

let user = {

name: "Вася",

};

console.log(userisAdmin); // true

Null (специальный тип данных)

Этот тип данных относится к специальным и состоит только из единственного значения null.

В JavaScript null не является «ссылкой на несуществующий объект» или «нулевым указателем», как в некоторых других языках. Это просто специальное значение, которое имеет смысл «ничего» или «значение неизвестно».

let players = null; // Данная запись говорит о том что игроки не известны, значение переменной не содержит ничего или оно неизвестно. Но эта запись говорит о том что переменная не неприсовенна (не undefined).

Undefined (специальный тип данных)

Значение undefined, как и null, образует свой собственный тип, состоящий из одного этого значения. Оно имеет смысл «значение не присвоено».

let empty;

console.log(empty); // выведет undefined

В явном виде undefined обычно не присваивают, так как это противоречит его смыслу. Для записи в переменную «пустого» или «неизвестного» значения используется null.

Object (составной тип данных)

Первых шесть , рассмотренных нами типов данных, называют "примитивами".

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

Объявляются объекты с помощью фигурных скобок, например :

let city = {

name : "Минск",

populate: 2000000,

};

Подробное описание объектов и работы с ними будет рассмотрено далее в курсе.

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

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

Несколько операторов мы знаем со школы – это обычные сложение +, умножение *, вычитание и так далее.

Термины: «унарный», «бинарный», «операнд»

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

Операнд – то, к чему применяется оператор. Например: 5 * 2 – оператор умножения с левым и правым операндами. Другое название: «аргумент оператора».

Унарным называется оператор, который применяется к одному выражению. Например, оператор унарный минус "-" меняет знак числа на противоположный:

let x = 1;

x = -x;

console.log( x ); // -1, применили унарный минус

Бинарным называется оператор, который применяется к двум операндам. Тот же минус существует и в бинарной форме:

let x = 1, y = 3;

console.log( y - x ); // 2, бинарный минус

Сложение строк, бинарный "+"

Обычно при помощи оператора "+" складывают числа. Но если бинарный оператор “+” применить к строкам, то он объединяет их в одну строку:

console.log('новая' + 'строка'); // новаястрока

Такую операцию называют "конкатенация строк". При сложении строк и числа получается строка.

Если хотя бы один аргумент является строкой, то второй будет также преобразован к строке!

Положение операнда "строка" в выражении не имеет значения. Конечный результат работы оператора “+” (конкатенация) приведет и вернет результат “строка”.

console.log(1 + "2"); // “12”

console.log(2 + "3"); // “23”

Эта особенность приведения числа - особенность оператора "+". Остальные арифметические операторы всегда приводят аргументы к числу.

console.log(6 - ‘2’); // 4

console.log(11 - ‘1’); // 10

Преобразование к числу, унарный оператор "+"

Унарный, то есть примененный к одному значению, плюс ничего не делает с числами:

console.log(+2); // 2

console.log( +( 1 - 2 ) ); // -1

Как видно, плюс ничего не изменил в выражениях. Результат – такой же, как и без него. Тем не менее, он широко применяется, так как его «побочный эффект» – преобразование значения в число. Например, когда мы получаем значения из HTML-полей или от пользователя, то они обычно в форме строк. А что, если их нужно, к примеру, сложить? Бинарный плюс сложит их как строки:

let apples = "2";

let oranges = "3";

console.log( apples + oranges ); // "23", так как бинарный плюс складывает строки

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

let apples = "2";

let oranges = "3";

console.log( +apples + +oranges ); // 5, число, оба операнда предварительно преобразованы в числа

С точки зрения математики такое изобилие плюсов может показаться странным. С точки зрения программирования – никаких разночтений: сначала выполняются унарные плюсы, приведут строки к числам, а затем – бинарный '+' их сложит.

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

Оператор typeof

Унарный оператор typeof возвращает тип аргумента.

Синтаксис оператора: typeof x.

typeof undefined // "undefined"

typeof 0 // "number"

typeof true // "boolean"

typeof "foo" // "string"

typeof {} // "object"

typeof null // "object" (1)

typeof function(){} // "function" (2)

Последние две строки помечены, потому что typeof ведет себя в них по-особому.

  1. Результат typeof null == "object" – это официально признанная ошибка в языке, которая сохраняется для совместимости. На самом деле null – это не объект, а отдельный тип данных.

  2. Функции мы пройдём чуть позже. Пока лишь заметим, что функции не являются отдельным базовым типом в JavaScript, а подвидом объектов. Но typeof выделяет функции отдельно, возвращая для них "function". На практике это весьма удобно, так как позволяет легко определить функцию.

Приоритет

В том случае, если в выражении есть несколько операторов – порядок их выполнения определяется приоритетом.

Из школы мы знаем, что умножение в выражении 2 * 2 + 1 выполняется раньше сложения, т.к. его приоритет выше, а скобки явно задают порядок выполнения. Но в JavaScript – гораздо больше операторов, поэтому существует целая таблица приоритетов.

Приоритет Название Обозначение
15 унарный плюс +
15 унарный минус -
14 умножение *
14 деление /
13 сложение +
13 вычитание -
3 присваивание =

Так как «унарный плюс» имеет приоритет 15, выше, чем 13 у обычного «сложения», то в выражении +apples + +oranges сначала сработали плюсы у apples и oranges, а затем уже обычное сложение.

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

Обратим внимание, в таблице приоритетов также есть оператор присваивания =.

У него – один из самых низких приоритетов: 3.

Именно поэтому, когда переменную чему-либо присваивают, например,

x = 2 * 2 + 1

сначала выполнится арифметика, а уже затем – произойдёт присваивание =.

let x = 2 * 2 + 1;

console.log( x ); // 5

Возможно присваивание по цепочке:

let a, b, c;

a = b = c = 2 + 2;

console.log( a ); // 4

console.log( b ); // 4

console.log( c ); // 4

Такое присваивание работает справа-налево, то есть сначала вычисляется самое правое выражение 2+2, присваивается в c, затем выполнится b = c и, наконец, a = b.

Оператор "=" возвращает значение

Все операторы возвращают значение. Вызов x = выражение не является исключением.

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

let a = 1;

let b = 2;

let c = 3 - (a = b + 1);

console.log( a ); // 3

console.log( c ); // 0

В примере выше результатом (a = b + 1) является значение, которое записывается в a (т.е. 3). Оно используется для вычисления c.

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

Взятие остатка %

Его результат a % b – это остаток от деления a на b.Например:

console.log( 5 % 2 ); // 1, остаток от деления 5 на 2

console.log( 8 % 3 ); // 2, остаток от деления 8 на 3

console.log( 6 % 3 ); // 0, остаток от деления 6 на 3

Инкремент/декремент: ++, --

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

Для этого существуют даже специальные операторы:

Инкремент ++ увеличивает на 1:

let i = 2;

i++;// более короткая запись для i = i + 1.

console.log(i); // 3

Декремент -- уменьшает на 1:

let i = 2;

i--;// более короткая запись для i = i - 1.

console.log(i); // 1

Важно:

Инкремент/декремент можно применить только к переменной. Код 5++ даст ошибку.

Вызывать эти операторы можно не только после, но и перед переменной: i++ (называется «постфиксная форма») или ++i («префиксная форма»).

Обе эти формы записи делают одно и то же: увеличивают на 1.

Тем не менее, между ними существует разница. Она видна только в том случае, когда мы хотим не только увеличить/уменьшить переменную, но и использовать результат в том же выражении.

Например:

let i = 1;

let a = ++i; // (*)

console.log(a); // 2

В строке (*) вызов ++i увеличит переменную, а затем вернёт ее значение в a. Так что в a попадёт значение i после увеличения.

Постфиксная форма i++ отличается от префиксной ++i тем, что возвращает старое значение, бывшее до увеличения.

В примере ниже в a попадёт старое значение i, равное 1:

let i = 1;

let a = i++; // (*)

console.log(a); // 1

Если результат оператора не используется, а нужно только увеличить/уменьшить переменную – без разницы, какую форму использовать:

let i = 0;

i++;

++i;

console.log( i ); // 2

Если хочется тут же использовать результат, то нужна префиксная форма:

let i = 0;

console.log( ++i ); // 1

Если нужно увеличить, но нужно значение переменной до увеличения – постфиксная форма:

let i = 0;

console.log( i++ ); // 0

Операторы сравнения и логические значения

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

Многие операторы сравнения знакомы нам из математики:

Больше/меньше: a > b, a < b.

Больше/меньше или равно: a >= b, a <= b.

Равно a == b.

Для сравнения используется два символа равенства '='. Один символ a = b означал бы присваивание.

«Не равно». В математике он пишется как ≠, в JavaScript – знак равенства с восклицательным знаком перед ним !=. Для проверки неравенства с учетом типа операндов используется оператор !==.

Логические значения

Как и другие операторы, сравнение возвращает значение. Это значение имеет логический тип.

Существует всего два логических значения:

true – имеет смысл «да», «верно», «истина».

false – означает «нет», «неверно», «ложь».

Например:

console.log( 2 > 1 ); // true, верно

console.log( 2 == 1 ); // false, неверно

console.log( 2 != 1 ); // true

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

let a = true; // присваивать явно

let b = 3 > 4; // или как результат сравнения

console.log( b ); // false

console.log( a == b ); // (true == false) неверно, выведет false

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

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

let dayToday = 'Monday';

if (answer == 'Sunday') {

console.log('Извините, у нас выходной');

}

Оператор if («если») получает условие, в примере выше это year != 2011. Он вычисляет его, и если результат – true, то выполняет команду.

Если нужно выполнить более одной команды – они оформляются блоком кода в фигурных скобках:

if (answer == 'Sunday') {

console.log('Извините, у нас выходной');

console.log('Приходите в будни!')

}

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

В логическом контексте:

  • Число 0, пустая строка "", null и undefined, а также NaN являются false

  • Остальные значения – true.

if (0) { // 0 преобразуется к false

...

}

Необязательный блок else («иначе») выполняется, если условие неверно:

let dayToday = 'Monday';

if (dayToday != 'Sunday') {

console.log('Добро пожаловать в наш магазин!');

} else {

console.log('Извините, у нас выходной');

}

Бывает нужно проверить несколько вариантов условия. Для этого используется блок else if ....

Например:

let dayToday = 'Monday';

if (dayToday == 'Sunday') {

console.log('Извините, у нас выходной');

} else if (dayToday == 'Holidays') {

console.log('Мы не работаем по праздникам!');

} else {

console.log('Добро пожаловать в наш магазин!');

}

В примере выше JavaScript сначала проверит первое условие, если оно ложно – перейдет ко второму – и так далее, до последнего else.

Тернарный оператор вопросительный знак "?"

Иногда нужно в зависимости от условия присвоить переменную. Например:

let isJavaScript;

let answer = 'JS';

if(answer === 'JavaScript') {

isJavaScript = true;

} else {

isJavaScript = false;

}

console.log(isJavaScript);

Оператор вопросительный знак '?' позволяет делать это короче и проще.

Т.к это тернарнарный оператор, то определяется для трех операндов:

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

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

let isJavaScript = answer === 'JavaScript' ? true : false;

В данном случае можно было бы обойтись и без оператора '?', т.к. сравнение само по себе уже возвращает true/false.

let isJavaScript = answer === 'JavaScript';

Взаимодействие с пользователем: alert, prompt, confirm

alert();

В этом разделе мы рассмотрим базовые UI операции: alert, prompt и confirm, которые позволяют работать с данными, полученными от пользователя.

alert(сообщение);

alert выводит на экран окно с сообщением и приостанавливает выполнение скрипта, пока пользователь не нажмёт «ОК».

alert("Привет");

Окно сообщения, которое выводится, является модальным окном. Слово «модальное» означает, что посетитель не может взаимодействовать со страницей, нажимать другие кнопки и т.п., пока не разберется с окном. В данном случае – пока не нажмёт на «OK».

prompt();

Функция prompt принимает два аргумента:

let result = prompt(title, default);

Она выводит модальное окно с заголовком title, полем для ввода текста, заполненным строкой по умолчанию default и кнопками OK/CANCEL.

Пользователь должен либо что-то ввести и нажать OK, либо отменить ввод кликом на CANCEL или нажатием Esc на клавиатуре.

Вызов prompt возвращает то, что ввёл посетитель – строку или специальное значение null, если ввод отменён.

сonfirm();

Синтаксис функции confirm :

let result = confirm(question);

confirm выводит модальное окно с вопросом с двумя кнопками: "Ок", “Cancel”

Результатом будет true при нажатии на OK и false - при нажатии на CANCEL(Esc)

Логические операторы ||(или), &&(и), !(не)

Для операций над логическими значениями в JavaScript есть || (ИЛИ), && (И) и ! (НЕ).

Хоть они и называются «логическими», но в JavaScript могут применяться к значениям любого типа и возвращают также значения любого типа.

|| (или)

Оператор ИЛИ выглядит как двойной символ вертикальной черты:

let result = a || b;

Логическое ИЛИ в классическом программировании работает следующим образом: "если хотя бы один из аргументов true, то возвращает true, иначе – false". В JavaScript, как мы увидим далее, это не совсем так, но для начала рассмотрим только логические значения.

Получается следующая «таблица результатов»:

console.log( true || true ); // true

console.log( false || true ); // true

console.log( true || false ); // true

console.log( false || false ); // false

Если значение не логического типа – то оно к нему приводится в целях вычислений. Например, число 1 будет воспринято как true, а 0 – как false:

if (1 || 0 ) { // сработает как true или false

console.log( 'верно' );

}

Обычно оператор ИЛИ используется в if, чтобы проверить, выполняется ли хотя бы одно из условий, например:

let hour = 9;

if (hour < 10 || hour > 18) {

console.log( 'Офис закрыт. Приходите с 10:00 до 18:00' );

}

Можно передать и больше условий. (hour < 10 || hour > 18 || isWeekend). При этом JS выполняет несколько таких ИЛИ слева направо. Если первый аргумент true , то результат заведомо будет true и остальные значения игнорируются.

Итак, как мы видим, оператор ИЛИ вычисляет ровно столько значений, сколько необходимо – до первого true.

При этом оператор ИЛИ возвращает то значение, на котором остановились вычисления. Причём, не преобразованное к логическому типу.

Например :

console.log( 1 || 0 ); // 1

console.log( true || 'неважно что' ); // true

let a = 0 || ‘’ || false;

console.log(a)

console.log( null || 1 ); // 1

console.log( undefined || 0 ); // 0

Итак, оператор || вычисляет операнды слева направо до первого «истинного» и возвращает его, а если все ложные – то последнее значение.

Иначе можно сказать, что "|| запинается на правде".

&& (И)

Оператор И пишется как два амперсанда &&.

В классическом программировании И возвращает true, если оба аргумента истинны, а иначе – false:

console.log( true && true ); // true

console.log( false && true ); // false

console.log( true && false ); // false

console.log( false && false ); // false

Пример с if :

let hour = 12;

let minute = 30;

if (hour == 12 && minute == 30) {

console.log( 'Время 12:30' );

}

Как и в ИЛИ, в И допустимы любые значения:

if (1 && 0) { // вычисляется как true && false

console.log( 'не сработает, т.к. условие ложно' );

}

К И применим тот же принцип «короткого цикла вычислений», но немного по-другому, чем к ИЛИ. Если левый аргумент – false, оператор И возвращает его и заканчивает вычисления. Иначе – вычисляет и возвращает правый аргумент. Например:

// Первый аргумент - true,

// Поэтому возвращается второй аргумент

console.log( 1 && 0 ); // 0

console.log( 1 && 5 ); // 5

// Первый аргумент - false,

// Он и возвращается, а второй аргумент игнорируется

console.log( null && 5 ); // null

console.log( 0 && "не важно" ); // 0

Можно передать и несколько значений подряд, при этом возвратится первое «ложное» (на котором остановились вычисления), а если его нет – то последнее:

console.log( 1 && 2 && null && 3 ); // null

Итак, оператор && вычисляет операнды слева направо до первого «ложного» и возвращает его, а если все истинные – то последнее значение.

Иначе можно сказать, что "&& запинается на лжи".

Приоритет у && больше, чем у ||

! (НЕ)

Оператор НЕ – самый простой. Он получает один аргумент. Синтаксис:

let result = !value;

Действия ! :

  1. Сначала приводит аргумент к логическому типу true/false.

  2. Затем возвращает противоположное значение

Например:

console.log( !true ); // false

console.log( !0 ); // true

Для преобразования типов, используют двойное НЕ (!!). Например :

console.log(!!"строка"); // true

console.log( !!null ); // false

Преобразование типов для примитивов

Система преобразования типов в JavaScript очень проста, но отличается от других языков. Поэтому она часто служит «камнем преткновения» для приходящих из других языков программистов.

Всего есть три преобразования:

  1. Строковое преобразование

  2. Числовое преобразование

  3. Преобразование к логическому значению

Строковое преобразование

Строковое преобразование происходит, когда требуется представление чего-либо в виде строки. Например, его производит функция alert.

let a = true;

alert( a ); // "true"

Можно также осуществить преобразование явным вызовом String(val):

console.log(String(null) === "null"); // true

Как видно из примеров выше, преобразование происходит наиболее очевидным способом, «как есть»: false становится "false", null – "null", undefined – "undefined" и т.п.

Также для явного преобразования применяется оператор "+", у которого один из аргументов строка (конкатенация). В этом случае он приводит к строке и другой аргумент, например:

console.log( true + "test" ); // "truetest"

console.log( "123" + undefined ); // "123undefined"

Численное преобразование

Численное преобразование происходит в математических функциях и выражениях, а также при сравнении данных различных типов (кроме сравнений ===, !==).

Для преобразования к числу в явном виде можно вызвать Number(val), либо, что проще, поставить перед выражением унарный плюс "+":

let a = +"123"; // 123

let num = prompt("Выберите свободное место", 30);

num = ‘я не знаю, давайте 24’;

var a = Number(num); // 24

Значение Преобразуется в...
undefined NaN
null 0
true / false 1 / 0
Строка Пробельные символы по краям обрезаются.Далее, если остаётся пустая строка, то 0, иначе из непустой строки "считывается" число, при ошибке результат NaN.

console.log( +" \n 123 \n \n" ); // 123

Ещё примеры:

Логические значения:

console.log( +true ); // 1

console.log( +false ); // 0

Сравнение разных типов – значит численное преобразование:

console.log( " 0" == 0 ); // true

При этом строка " 0" преобразуется к числу, как указано выше: начальные и конечные пробелы обрезаются, получается строка "0", которая равна 0.

С логическими значениями:

console.log( "" == false );

console.log( "1" == true );

Здесь сравнение "==" снова приводит обе части к числу. В первой строке слева и справа получается 0, во второй 1.

Логическое преобразование

Преобразование к true/false происходит в логическом контексте, таком как if(value), и при применении логических операторов.

Все значения, которые интуитивно «пусты», становятся false. Их несколько: 0, пустая строка, null, undefined и NaN.

Остальное, в том числе и любые объекты – true.

Полная таблица преобразований:

Значение Преобразуется в...
undefined, null false
Числа Все true, кроме 0, NaN -- false.
Строки Все true, кроме пустой строки "" -- false
Объекты Всегда true

**Для явного преобразования используется двойное логическое отрицание !!value или вызов Boolean(value). **

Строка "0" становится true

В отличие от многих языков программирования (например PHP), "0" в JavaScript является true, как и строка из пробелов:

console.log( !!"0" ); // true

console.log( !!" " ); // любые непустые строки, даже из пробелов - true!

Итого

В JavaScript есть три преобразования:

Строковое: String(value) – в строковом контексте или при сложении со строкой. Работает очевидным образом.

Численное: Number(value) – в численном контексте, включая унарный плюс +value. Происходит при сравнении разных типов, кроме строгого равенства.

Логическое: Boolean(value) – в логическом контексте, можно также сделать двойным НЕ: !!value.

Точные таблицы преобразований даны выше.

Особым случаем является проверка равенства с null и undefined. Они равны друг другу, но не равны чему бы то ни было ещё, этот случай прописан особо в спецификации.

Циклы while / for

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

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

Для многократного повторения одного участка кода – предусмотрены циклы.

**Цикл while **

Имеет следующий вид :

while (условие) { // тело цикла ( код )

}

Пока условие верно – выполняется код из тела цикла.

Например, цикл ниже выводит i пока i < 3:

var i = 0;

while (i < 3) {

console.log( i );

i++;

}

Повторение цикла по-научному называется «итерация». Цикл в примере выше совершает три итерации.

Если бы i++ в коде выше не было, то цикл выполнялся бы (в теории) вечно. На практике, браузер выведет сообщение о «зависшем» скрипте и посетитель его остановит.

Условие в скобках интерпретируется как логическое значение, поэтому вместо while (i!=0) обычно пишут while (i):

let i = 3;

while (i) { // при i, равном 0, значение в скобках будет false и цикл остановится

console.log( i );

i--;

}

Цикл for

Применяется чаще всего. Его вид:

for (начало; условие; шаг) {

// ... тело цикла ...

}

Пример цикла, который выполняет alert(i) для i от 0 до 2 включительно (до 3):

let i;

for (i = 0; i < 3; i++) {

console.log( i );

}

Здесь:

  • Начало: i = 0.

  • Условие: i < 3

  • Шаг: i++.

  • Тело: alert(i), т.е. код внутри фигурных скобок

Цикл выполняется так:

  1. Начало: i = 0 выполняется один-единственный раз, при заходе в цикл.

  2. Условие: i < 3 проверяется перед каждой итерацией и при входе в цикл, если оно нарушено, то происходит выход.

  3. Тело: alert(i).

  4. Шаг: i++ выполняется после тела на каждой итерации, но перед проверкой условия.

  5. **Идти на шаг 2 **

Иными словами, поток выполнения: начало → (если условие → тело → шаг) → (если условие → тело → шаг) → … и так далее, пока верно условие.

В цикле также можно определить переменную в роли счетчика (так обычно и делается ):

for (let i = 0; i < 3; i++) {

console.log(i); // 0, 1, 2

}

Эта переменная будет видна и за границами цикла, в частности, после окончания цикла i станет равно 3.

Помимо цикла for, существует также цикл for … in , который будет рассматриваться в работе с Объектами. Такая конструкция перебирает свойства объекта.

Прерывание цикла: break

Выйти из цикла можно не только при проверке условия но и, вообще, в любой момент. Эту возможность обеспечивает директива break.

Например, следующий код подсчитывает сумму вводимых чисел до тех пор, пока посетитель их вводит, а затем – выдаёт:

let sum = 0;

while (true) {

let value = +prompt("Введите число", ''); // записываем приведенное к числу значение в переменную value

if (!value) break; // (*) // если значение пустое (не value), то прерываем цикл.

sum += value; // если значение выше было не пустым, то считаем сумму предыдущего значения переменной sum и value и записываем в sum.

}

console.log( 'Сумма: ' + sum ); // выводим сумму, если цикл был остановлен директивой break.

Директива break в строке (*), если посетитель ничего не ввёл, полностью прекращает выполнение цикла и передаёт управление на строку за его телом, то есть на alert.

Вообще, сочетание «бесконечный цикл + break» – отличная штука для тех ситуаций, когда условие, по которому нужно прерваться, находится не в начале-конце цикла, а посередине.

Следующая итерация : continue

Директива continue прекращает выполнение текущей итерации цикла.

Она – в некотором роде «младшая сестра» директивы break: прерывает не весь цикл, а только текущее выполнение его тела, как будто оно закончилось.

Её используют, если понятно, что на текущем повторе цикла делать больше нечего.

Например, цикл ниже использует continue, чтобы не выводить чётные значения:

for (let i = 0; i < 10; i++) {

if (i % 2 == 0) continue;

console.log(i);

}

Для чётных i срабатывает continue, выполнение тела прекращается и управление передаётся на следующий проход for.

Метки для break/continue

Бывает нужно выйти одновременно из нескольких уровней цикла.

Например, внутри цикла по i находится цикл по j, и при выполнении некоторого условия мы бы хотели выйти из обоих циклов сразу:

outer: for (let i = 0; i < 3; i++) {

for (let j = 0; j < 3; j++) {

let input = prompt('Значение в координатах '+i+','+j, '');

// если отмена ввода или пустая строка -

// завершить оба цикла

if (!input) break outer; // (*)

}

}

console.log('Готово!');

В коде выше для этого использована метка.

Метка имеет вид "имя:", имя должно быть уникальным. Она ставится перед циклом, вот так:

outer: for (let i = 0; i < 3; i++) { ... }

Можно также выносить её на отдельную строку:

outer:

for (let i = 0; i < 3; i++) { ... }

Вызов break outer ищет ближайший внешний цикл с такой меткой и переходит в его конец.

В примере выше это означает, что будет разорван самый внешний цикл и управление перейдёт на alert.

Директива continue также может быть использована с меткой, в этом случае управление перепрыгнет на следующую итерацию цикла с меткой.

Итого

JavaScript поддерживает три вида циклов:

while – проверка условия перед каждым выполнением.

do..while – проверка условия после каждого выполнения.

for – проверка условия перед каждым выполнением, а также дополнительные настройки.

Чтобы организовать бесконечный цикл, используют конструкцию while(true). При этом он, как и любой другой цикл, может быть прерван директивой break.

Если на данной итерации цикла делать больше ничего не надо, но полностью прекращать цикл не следует – используют директиву continue.

Обе этих директивы поддерживают «метки», которые ставятся перед циклом. Метки – единственный способ для break/continue повлиять на выполнение внешнего цикла.

Метки не позволяют прыгнуть в произвольное место кода, в JavaScript нет такой возможности.

Конструкция switch

Конструкция switch заменяет собой сразу несколько if.

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

Синтаксис :

switch(x) {

case 'value1': // if (x === 'value1')

...

[break]

case 'value2': // if (x === 'value2')

...

[break]

default:

...

[break]

}

  • Переменная x проверяется на строгое равенство первому значению value1, затем второму value2 и так далее.

  • Если соответствие установлено – switch начинает выполняться от соответствующей директивы case и далее, до ближайшего break (или до конца switch).

  • Если ни один case не совпал – выполняется (если есть) вариант default.

При этом case называют вариантами switch.

Пример использования switch :

let a = 2 + 2;

switch (a) {

case 3:

console.log( 'Маловато' );

break;

case 4:

console.log( 'В точку!' );

break;

case 5:

console.log( 'Перебор' );

break;

default:

console.log( 'Я таких значений не знаю' );

}

Здесь оператор switch последовательно сравнит a со всеми вариантами из case.

Сначала 3, затем – так как нет совпадения – 4. Совпадение найдено, будет выполнен этот вариант, со строки alert('В точку!') и далее, до ближайшего break, который прервёт выполнение.

Если break нет, то выполнение пойдёт ниже по следующим case, при этом остальные проверки игнорируются.

Пример без break:

let a = 2 + 2;

switch (a) {

case 3:

alert( 'Маловато' );

case 4:

alert( 'В точку!' );

case 5:

alert( 'Перебор' );

default:

alert( 'Я таких значений не знаю' );

}

В примере выше последовательно выполнятся три alert:

console.log( 'В точку!' );

console.log( 'Перебор' );

console.log( 'Я таких значений не знаю' );

В case могут быть любые выражения, в том числе включающие в себя переменные и функции :

let a = 1;

let b = 0;

switch (a) {

case b + 1:

console.log( 1 );

break;

default:

console.log('нет-нет, выполнится вариант выше')

}

Группировка case

Несколько значений case можно группировать.

В примере ниже case 3 и case 5 выполняют один и тот же код:

let a = 2+2;

switch (a) {

case 4:

console.log('Верно!');

break;

case 3: // (*)

case 5: // (**)

console.log('Неверно!');

console.log('Немного ошиблись, бывает.');

break;

default:

console.log('Странный результат, очень странный');

}

При case 3 выполнение идёт со строки (*), при case 5 – со строки (**).

Тип имеет значение

Следующий пример принимает значение от посетителя.

let arg = prompt("Введите arg?")

switch (arg) {

case '0':

case '1':

console.log( 'Один или ноль' );

case '2':

console.log( 'Два' );

break;

case 3:

console.log( 'Никогда не выполнится' );

default:

console.log('Неизвестное значение: ' + arg)

}

  • При вводе 0 выполнится первый alert, далее выполнение продолжится вниз до первого break и выведет второй alert('Два'). Итого, два вывода alert.

  • При вводе 1 произойдет то же самое.

  • При вводе 2, switch перейдет к case '2', и сработает единственный alert('Два').

  • При вводе 3, switch перейдет на default. Это потому, что prompt возвращает строку '3', а не число. Типы разные. Оператор switch предполагает строгое равенство ===, так что совпадения не будет.

Функции

Зачастую нам надо повторять одно и то же действие во многих частях программы.

Например, красиво вывести сообщение необходимо при приветствии посетителя, при выходе посетителя с сайта, ещё где-нибудь.

Чтобы не повторять один и тот же код во многих местах, придуманы функции. Функции являются основными «строительными блоками» программы.

Примеры встроенных функций вы уже видели – это alert(message), prompt(message, default) и confirm(question). Но можно создавать и свои.

Объявление

Пример объявления функции:

function sayHi() {

console.log( 'Привет!' );

}

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

Объявленная функция доступна по имени, например:

function sayHi() {

console.log( 'Привет!' );

}

sayHi();

sayHi();

Этот код выведет сообщение два раза. Уже здесь видна главная цель создания функций: избавление от дублирования кода.

Если понадобится поменять сообщение или способ его вывода – достаточно изменить его в одном месте: в функции, которая его выводит.

Локальные переменные

Функция может содержать локальные переменные, объявленные через var, let, const. Такие переменные видны только внутри функции:

function showMessage() {

let message = 'Привет, я - Вася!'; // локальная переменная

console.log( message );

}

showMessage(); // 'Привет, я - Вася!'

console.log( message ); // <-- будет ошибка, т.к. переменная видна только внутри.

Блоки if /else, switch, for, while, do..while не влияют на область видимости переменных.

При объявлении переменной в таких блоках, она всё равно будет видна во всей функции. Вспомните, если сделать конструкцию for не в функции и объявить переменную счетчик ( i ), то такая переменная будет доступна в коде ниже.

function counter() {

// переменные i,j не будут уничтожены по окончании цикла

for (var i = 0; i < 3; i++) {

var j = i * 2;

}

console.log(i); // i=3, последнее значение i, при нём цикл перестал работать

console.log(j); // j=4, последнее значение j, которое вычислил цикл

}

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

Объявления переменных в примере выше можно передвинуть вверх, это ни на что не повлияет:

function count() {

let i, j; // передвинули объявления var в начало

for (i = 0; i < 3; i++) {

j = i * 2;

}

console.log( i ); // i=3

console.log( j ); // j=4

}

Внешние переменные

Функция может обратиться ко внешней переменной, например:

let userName = 'Вася';

function showMessage() {

let message = 'Привет, я ' + userName;

console.log(message);

}

showMessage(); // Привет, я Вася

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

let userName = 'Вася';

function showMessage() {

userName = 'Петя'; // (1) присвоение во внешнюю переменную

let message = 'Привет, я ' + userName;

console.log( message );

}

showMessage();

console.log( userName ); // Петя, значение внешней переменной изменено функцией

Конечно, если бы внутри функции, была бы объявлена своя локальная переменная var userName, то все обращения использовали бы её, и внешняя переменная осталась бы неизменной.

Переменные, объявленные на уровне всего скрипта, называют «глобальными переменными».

В примере выше переменная userName – глобальная.

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

В будущем, когда мы лучше познакомимся с основами JavaScript, в теме "Замыкания, функции изнутри", мы более детально рассмотрим внутренние механизмы работы переменных и функций.

Параметры

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

Например, этот код выводит два сообщения:

function showMessage(from, text) { // параметры from, text

from = "** " + from + " **"; // здесь может быть сложный код оформления

сonsole.log(from + ': ' + text);

}

showMessage('Маша', 'Привет!');

showMessage('Маша', 'Как дела?');

function sayHi(to, text, times) {

if(!times) {

console.log(to + ": " + text);

} else if (+times) {

for(times; times > 0; times--) {

		console.log(to + " : " + text);

}

} else {

console.log('Warning, tims is not a number');

}

}

sayHi('Me', 'Hi');

sayHi('Me', 'Hi', '5');

Параметры копируются в локальные переменные функции.

Например, в коде ниже есть внешняя переменная from, значение которой при запуске функции копируется в параметр функции с тем же именем. Далее функция работает уже с параметром:

let from = "Маша";

let message = "Привет";

function showMessage(from, text) {

//"Маша"

from = '** ' + from + ' **'; // меняем локальную переменную from

// ** Маша **

console.log( from + ': ' + text );

}

showMessage(from, message);

console.log( from ); // старое значение from без изменений, в функции была изменена копия

Аргументы по умолчанию

Функцию можно вызвать с любым количеством аргументов.

Если параметр не передан при вызове – он считается равным undefined.

Например, функцию показа сообщения showMessage(from, text) можно вызвать с одним аргументом:

showMessage("Маша");

При этом можно проверить, и если параметр не передан – присвоить ему значение «по умолчанию»:

function showMessage(from, text) {

if (!text) {

text = 'текст не передан';

}

console.log( from + ": " + text );

}

showMessage("Маша", "Привет!"); // Маша: Привет!

showMessage("Маша"); // Маша: текст не передан

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

Для указания значения «по умолчанию», то есть, такого, которое используется, если аргумент не указан, используется два способа:

  1. Можно проверить, равен ли аргумент undefined, и если да – то записать в него значение по умолчанию. Этот способ продемонстрирован в примере выше.

  2. Использовать оператор ||:

function showMessage(from, text) {

text = text || 'текст не передан';

}

Второй способ считает, что аргумент отсутствует, если передана пустая строка, 0, или вообще любое значение, которое в логическом контексте является false.

Если аргументов передано больше, чем надо, например showMessage("Маша", "привет", 1, 2, 3), то ошибки не будет. Но, чтобы получить такие «лишние» аргументы, нужно будет прочитать их из специального объекта arguments, который мы рассмотрим в главе Псевдомассив аргументов "arguments".

Возврат значения

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

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

function sum(a,b){

if (!a && !b) {

return;

} else {

return a + b;

} }

Для возврата значения используется директива return.

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

Вызовов return может быть и несколько, например:

function checkAge(age) {

if (age > 18) {

return true;

} else {

return confirm('Родители разрешили?');

}

}

let age = +prompt('Ваш возраст?');

if (checkAge(age)) {

console.log( 'Доступ разрешен' );

} else {

console.log( 'В доступе отказано' );

}

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

Например:

function checkAge(age) {

if (age > 18) {

return true;

} else {

return confirm('Родители разрешили?');

}

}

function showMovie(age) {

if (!checkAge(age)) {

return;

}

console.log( "Фильм не для всех" ); // (*)

// ...

}

В коде выше, если сработал if, то строка (*) и весь код под ней никогда не выполнится, так как return завершает выполнение функции.

Выбор имени функции

Функции, которые начинаются с "show" – что-то показывают:

showMessage(..) // префикс show, "показать" сообщение

Функции, начинающиеся с "get" – получают, и т.п.:

getAge(..) // get, "получает" возраст

calcD(..) // calc, "вычисляет" дискриминант

createForm(..) // create, "создает" форму

checkPermission(..) // check, "проверяет" разрешение,

isNumber() // для определения логического значения

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

Одна функция – одно действие

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

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

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

Например, функция проверки данных (скажем, "validate") не должна показывать сообщение об ошибке. Её действие – проверить.

Итого

Объявление функции имеет вид:

function имя(параметры, через, запятую) {

код функции;

}

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

  • Параметры функции копируются в её локальные переменные.

  • Можно объявить новые локальные переменые при помощи var, let

или const.

  • Значение возвращается оператором return ....

  • Вызов return тут же прекращает функцию.

  • Если return; вызван без значения, или функция завершилась без return, то её результат равен undefined.

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

  • Это делает очевидным общий поток выполнения – что передаётся в функцию и какой получаем результат.

  • Это предотвращает возможные конфликты доступа, когда две функции, возможно написанные в разное время или разными людьми, неожиданно друг для друга меняют одну и ту же внешнюю переменную.

Именование функций:

  • Имя функции должно понятно и чётко отражать, что она делает. Увидев её вызов в коде, вы должны тут же понимать, что она делает.

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

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

Функциональные выражения

В JavaScript функция является значением, таким же как число и строка.

Как и любое значение, объявленную функцию можно вывести на экран :

function sayHi(){

console.log("Привет");

}

console.log(sayHi); // выведет код функции на экран

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

Функцию можно скопировать в другую переменную :

function sayHi(){ // объявили функцию sayHi (1)

console.log("Привет");

}

let func = sayHi; // cкопировали в переменную как значение (2)

func(); // Вызов функции (3)

window.sayHi = null;

sayHi(); // Вызов функции приведет к ошибке (4)

  1. Объявление (1) как бы говорит интерпретатору "Создай функцию и помести ее в переменную sayHi() (неявное создание переменной , а сама функция - значение)

  2. В строке (2) мы копируем функцию в новую переменную func. После sayHi нет скобок. Если бы они были, то вызов let func = sayHi(); записал бы в func результат работы sayHi();

  3. На момент (3) функцию можно вызвать и как sayHi() и как func()

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

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

Это действие можно запустить через скобки (), а можно и скопировать в другую переменную, как было продемонстрировано выше.

Объявление Function Expression

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

Он называется Function Expression (функциональное выражение) и выглядит так :

let f = function (параметры) {

// тело функции

}

Например :

let sayHi = function (person) {

console.log("Привет, “ + person );

}

sayHi("Вася");

**Сравнение c Function Declaration **

"Классическое" объявление функции, о котором мы говорили до этого, вида function имя ( параметры ) { … }, называется в спецификации языка Function Declaration

  • Function Declaration - функция, объявленная в основном потоке кода.

  • Function Expression - объявление функции в контексте какого-либо выражения, например присваивания.

Несмотря на немного разный вид, по сути эти две записи делают одно и то же:

// Function Declaration

function sum (a, b) {

return a + b;

}

//Function Expression

let sum = function (a, b) {

return a + b;

}

Оба этих объявления говорят интерпретатору : "Объяви переменную sum, создай функцию с указанным кодом и параметрами и сохрани ее в sum".

Основное отличие между ними : функции, объявленные как Function Declaration, создаются интерпретатором до выполнения кода. (первый проход интерпретатора)

Поэтому такие функции можно вызвать до объявления, например :

sayHi("Вася");

function sayHi(name) {

console.log("Привет, " + name);

}

А если бы это было объявление функции (Function Expression), то такой вызов бы не сработал :

sayHi("Вася"); // ошибка

var sayHi = function (name) {

console.log("Привет, “ + name);

}

Так происходит потому что JavaScript перед запуском кода ( на первом проходе ) ищет все Function Declaration ( их найти легко : они не являются частью выражений и начинаются с ключевого слова function) и обрабатывает их.

А Function Expression создаются в процессе выполнения выражения, в котором созданы, в данном случае - функция будет создана при операции присваивания sayHi = function …

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

Можно расположить функции внизу, а их вызов – сверху или наоборот.

Условное объявление функции** **

В некоторых случаях «дополнительное удобство» Function Declaration может сослужить плохую службу.

Например, попробуем, в зависимости от условия, объявить функцию sayHi по-разному:

let age = +prompt("Сколько вам лет?", 20); // 30

if (age >= 18) {

function sayHi() {

console.log( 'Прошу вас!' ); 

}

} else {

function sayHi() {

console.log( 'До 18 нельзя' ); 

}

}

sayHi();

Function Declaration видны только внутри блока, в котором объявлены. Тут будет ошибка (при условии выполнения кода в ‘use strict’).

А если использовать Function Expression ?

let name = +prompt('Введите ваше имя');

let age = +prompt('Введите ваш возраст');

let getWelcomeUserText;

if (age >= 18) {

getWelcomeUserText = function() {

return "Здравствуйте уважаемый, " + name; 

}

} else {

getWelcomeUserText = function() {

return "Приветик, " + name; 

}

}

getWelcomeUserText();

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

Анонимные функции

Взглянем еще на один пример - функцию ask( question, yes, no) с тремя параметрами :

question - строка вопрос

yes - функция

**no **- функция

Эта функция выводит вопрос (question) и, в зависимости от согласия пользователя, вызывает либо функцию yes() , либо no() :

function ask(question, yes, no) {

if (confirm (question)){ yes();

} else {

no(); 

}

function doSomething() {

console.log("Вы согласились. ")

window.replace = "http://go.site.ru";

}

function notDo() { console.log("Вы отменили действие");

window.replace = "http://goodbye.site.ru";

}

//

ask("Хотите перейти по данной ссылке?", doSomething, notDo);

Тот же самый код можно написать более кратко :

function ask (question, yes, no){

if (confirm(question)){

yes();

} else {

no();

}

ask ("Хотите перейти по данной ссылке ?" , function () { alert(”Вы согласны”); } , function () { alert(“Вы отменили действие.”); } ;

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

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

Зачем записывать функцию в переменную, хранить ее в нашем коде, если мы не собираемся ее вызывать еще раз? Можно объявить ее там, где эта функция нужна.

Такого рода код естественен, он соответствует "духу" JavaScript.

Итого

Функции в JavaScript являются значениями. Их можно присваивать, передавать, создавать в любом месте кода.

  • Если функция объявлена через ключевое слово function в основном потоке кода, то это Function Declaration

  • Если функция создана как часть выражения (например в выражении присваивания переменной или при передачи в параметрах) , то это Function Expression

Между этими двумя основными способами создания функции есть следующие различия :

		     **Function Declaration **             **Function Expression**
Время создания До выполнения первой строчки кода. Когда управление достигает строки с функцией.
Можно вызвать до объявления Да (т.к. создаётся заранее) Нет
Условное объявление в if Не работает Работает

Иногда в коде начинающих разработчиков можно увидеть много Function Expression. Почему-то, видимо, не очень понимая происходящее, функции решают создавать как var func = function(), но в большинстве случаев обычное объявление функции – лучше.

Если нет явной причины использовать Function Expression – предпочитайте Function Declaration.

// Function Expression

let f = function() { ... }

// Function Declaration

function f() { ... }

Function Declaration короче и лучше читается. Дополнительный бонус – такие функции можно вызывать до того, как они объявлены.

Используйте Function Expression только там, где это действительно нужно и удобно.

Всё вместе : Особенности JavaScript

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

**Структура кода **

Команды (инструкции) разделяются точкой с запятой :

console.log("Привет"); console.log(“Мир”);

Как правило, перевод строки также подразумевает точку с запятой :

console.log("Привет")

console.log("Мир)

Однако, иногда JavaScript не вставляет точку с запятой. Например:

var a = 2

+3

console.log(a); // выведет 5

Бывают случаи, когда это ведет к ошибкам, которые достаточно трудно найти и исправить, например :

console.log("Привет")

[1, 2].forEach(console.log)

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

Поэтому в JavaScript рекомендуется точки с запятой ставить. Сейчас это, фактически, общепринятый стандарт.

Поддерживаются однострочные (//) и многострочные (/.../) комментарии.

Переменные и типы

  • Объявляются директивой var. Могут хранить любое значение :

var x = 5; var name = "Витя";

  • Есть 5 "примитивных" типов и объекты :

var a = 1; //Число var b = “Text”; // Строка var c = true; // Булево значение var d = null; // Спец. значение (само себе тип) var e = undefined // Спец. значение (само себе тип)

Также есть специальные числовые значения Infinity (бесконечность) и NaN.

Значение NaN обозначает ошибку и является результатом числовой операции, если она некорректна.

  • Значение null не является "Ссылкой на нулевой указатель/объект"! Это просто специально значение.

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

Например :

var age = null; // возраст неизвестен

  • **Значение ****undefined **означает "значение не присвоено"

var x; console.log(x) // undefined

Данное значение можно присвоить явным образом : x = undefined, но так делать не рекомендуется.

  • В имени переменной могут быть использованы любые цифры, буквы, но имя не должно начинаться с цифры. Символы $ , _ - допускаются наравне с буквами.

Строгий режим

Для того, чтобы интерпретатор работал в режиме максимального соответствия современному стандарту, нужно начинать скрипт директивой 'use strict';

'use strict';

...

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

Одно из важных изменений в современном стандарте – все переменные нужно объявлять через var.

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

Взаимодействие с посетителем

Простейшие функции для взаимодействия с пользователем в браузере:

**prompt ( вопрос, значение по умолчанию ) ; **

Задает вопрос через модальное окно и возвращает значение (строку), либо null, если пользователь нажал "Cancel" или закрыл окно клавишей esc.

**confirm (вопрос); **

Задает вопрос через модальное с кнопками "OK" и “Cancel”. Возвращает true/false соответственно.

alert();

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

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

Особенности операторов

  • **Для сложения строк используется бинарный оператор + **

Если хотя бы один аргумент (операнд) строка, то другой тоже приводится к строке :

console.log ( 1 + 2 ) ; // 3, число
console.log ( ‘1’ + 2 ); // 12, строка
console.log ( 1 + ‘2’ ); // 12, строка
  • **Сравнение === проверяет точное равенство, включая одинаковый тип. **Это самый надежный способ сравнения

  • **Сравнения через операторы ==, <, <=, >, >= осуществляют числовое приведение типа :

** console.log ( 0 == false ); // true console.log ( true > 0 ); //true

Исключение - сравнение двух строк, которое осуществляется лексикографически. Также значения null и undefined при == равны друг другу и не равны ничему еще. А при операторах больше/меньше происходит приведение Null к 0, а undefined к NaN.

Такое приведение может привести к неочевидным результатам, поэтому лучше всего использовать для сравнения с null/undefined оператор ===. Оператор == тоже можно, если не нужно отличать по типам null от undefined.

console.log( null > 0 ); // false, т.к. null преобразовано к 0

console.log( null >= 0 ); // true, т.к. null преобразовано к 0

console.log( null == 0 ); // false, в стандарте явно указано, что null равен лишь undefined

С точки зрения здравого смысла такое невозможно. Значение null не равно нулю и не больше, но при этом null >= 0 возвращает true!

  • Сравнение строк – лексикографическое, символы сравниваются по своим unicode-кодам.

Поэтому получается, что строчные буквы всегда больше, чем прописные:

console.log ( ‘а’ > ‘Я’ ); // true

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

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

В JavaScript есть логические операторы: И ( обозначается && ), ИЛИ ( обозначается || ), и НЕ ( обозначается ! ). Они интерпретируют любое значение как логическое.

Как и в большинстве языков программирования, в логических операторах используется "короткий цикл" вычислений. Например , вычисление выражения 1 && 0 && 2 остановится после первого И (&&) , т.к понятно что результат будет ложным (ноль интерпретируется как false).

Результатом логического оператора служит последнее значение в коротком цикли вычислений.

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

var res = 1 && 0; // в переменную res запишется 0 console.log (res); // выведет 0
console.log( 1 && 2 && 3 ); // выведет 3

Циклы

  • Поддерживаются три вида циклов :

//1

while (a > 0) { //пока … a--; }

//2

do {

} while (users > 0) {

};

//3

for (var i = 0; i < 10; i++) { console.log(i); }

  • Переменную можно объявить прямо в цикле, но видна она будет и за его пределами.

  • Поддерживаются директивы break/continue для выхода из цикла/перехода на следующую итерацию.

Для выхода одновременно из нескольких уровней цикла можно задать метку.

Синтаксис : "имя_метки:", которая ставится только перед циклами и блоками, например :

outer: //метка for(var i = 0; i < 10; i++) { … for(var j = 0; j < 10; j++) { … break outer; } }

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

**Конструкция switch **

При сравнении, конструкция switch использует строгое сравнение (===).

var age = prompr ("Сколько вам лет?", “”); //’18'

switch (age) {

case 18: console.log( "Никогда не сработает" ); // prompt возвращает строку

case ‘18’: console.log( “Вход разрешен!”); break;

default: console.log( ‘Сработает при любом значении, не совпавшим с case’); }

Функции

Синтаксис функции в JavaScript :

function имя_функции (параметры) {

// тело функции }

//объявление

function sum(a, b){ return a + b;

}

sum ( 1, 121); // вызов

  • sum - имя функции, ограничения на имя функции такое же, что и на имя переменной

  • Переменные, объявленные через var внутри функции называются локальными и видны везде внутри функции. Блоки if, for и др. на видимость не влияют

  • Параметры копируются в локальные переменные a, b

  • Функция без return считается возвращающей undefined. Использование return без значения также возвращает undefined

**Function Expression и Function Declaration **

Функция в JavaScript является обычным значением.

Её можно создать в любом месте кода и присвоить в переменную :

var sum = function (a, b) {

var result = a + b;

return result; };

Такой синтаксис, при котором функция объявляется в контексте выражения (в данном случае выражения присваивания), называется Function Expression. Обычный синтаксис, при котором функция объявляется в основном потоке кода, называется Function Declaration.

Функции объявленные через Function Declaration, отличаются от Function Expression тем, что интерпретатор создает их при входе в область видимости (в начале выполнения скрипта, на первом проходе), так что они работают до объявления.

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

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

Итого

В этой части мы познакомились с основами JavaScript. Данные знания помогут обойти большинство "граблей" и для написания хорошего кода без “костылей” и “велосипедов”.

Структуры данных в JavaScript

** **image alt text

Введение в методы и свойства

Все значения в JavaScript, за исключением null и undefined, содержат набор вспомогательных функций и значений, доступных «через точку».

Такие функции называют «методами», а значения – «свойствами». Здесь мы рассмотрим основы использования свойств и методов.

Свойство str.length

console.log( "Привет, мир!".length ); // 12

Можно и записать строку в переменную, а потом запросить её свойство:

let str = "Привет, мир!";

console.log(str.length ); // 12

Метод str.toUpperCase()

let hello = "Привет, мир!";

console.log(hello.toUpperCase()); // "ПРИВЕТ, МИР!"

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

Есть методы и у чисел, например num.toFixed(n). Он округляет число num до n знаков после запятой, при необходимости добивает нулями до данной длины и возвращает в виде строки (удобно для форматированного вывода):

var n = 12.345;

alert( n.toFixed(2) ); // "12.35"

alert( n.toFixed(0) ); // "12"

alert( n.toFixed(5) ); // "12.34500"

*методу числа можно обратиться и напрямую: *

alert( 12.34.toFixed(1) ); // 12.3

...Но если число целое, то будет проблема:

alert(12.toFixed(1)); // ошибка!

Ошибка произойдет потому, что JavaScript ожидает десятичную дробь после точки.

Это – особенность синтаксиса JavaScript. Вот так – будет работать:

alert( 12..toFixed(1) ); // 12.0

Почти все значения в JavaScript, кроме разве что null и undefined имеют методы и свойства.

Далее мы подробно разберём основные свойства и методы структур данных в JavaScript.

Числа

Все числа в JavaScript, как целые так и дробные, имеют тип Number и хранятся в 64-битном формате IEEE-754, также известном как «double precision».

Здесь мы рассмотрим различные тонкости, связанные с работой с числами в JavaScript.

**Способы записи

**

В JavaScript можно записывать числа не только в десятичной, но и в шестнадцатеричной (начинается с 0x) системе счисления:

alert( 0xFF ); // 255 в шестнадцатеричной системе

Также доступна запись в «научном формате» (ещё говорят «запись с плавающей точкой»), который выглядит как <число>e<количество нулей>.

Например, 1e3 – это 1 с 3 нулями, то есть 1000.

// еще пример научной формы: 3 с 5 нулями

alert(3e5); // 300000

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

// здесь 3 сдвинуто 5 раз вправо, за десятичную точку.

alert( 3e‐5 ); // 0.00003 <‐‐ 5 нулей, включая начальный ноль

**Деление на ноль, Infinity **

Представьте, что вы собираетесь создать новый язык... Люди будут называть его «JavaScript» (или «LiveScript»... неважно). Что должно происходить при попытке деления на ноль? Как правило, ошибка в программе... Во всяком случае, в большинстве языков программирования это именно так.

Но создатель JavaScript решил пойти математически правильным путем. Ведь чем меньше делитель, тем больше результат. При делении на очень-очень маленькое число должно получиться очень большое. В математическом анализе это описывается через пределы, и если подразумевать предел, то в качестве результата деления на 0 мы получаем «бесконечность», которая обозначается символом ∞ (в JavaScript Infinity).

alert( 1 / 0 ); // Infinity

alert( 12345 / 0 ); // Infinity

Infinity – особенное численное значение, которое ведет себя в точности как математическая бесконечность ∞.

  • Infinity больше любого числа.

  • Добавление к бесконечности не меняет её.

alert( Infinity > 1234567890 ); // true

alert( Infinity + 5 == Infinity ); // true

Бесконечность можно присвоить и в явном виде: var x = Infinity.

Бывает и минус бесконечность ‐Infinity:

alert( ‐1 / 0 ); // ‐Infinity

Бесконечность можно получить также, если сделать ну очень большое число, для которого количество разрядов в двоичном представлении не помещается в соответствующую часть стандартного 64-битного формата, например:

alert( 1e500 ); // Infinity

**NaN **

Если математическая операция не может быть совершена, то возвращается специальное значение NaN (Not-A-Number).

Например, деление 0/0 в математическом смысле неопределено, поэтому его результат NaN:

alert( 0 / 0 ); // NaN

Значение NaN используется для обозначения математической ошибки и обладает следующими свойствами:

  • Значение NaN – единственное в своем роде, которое не равно ничему, включая себя.

Следующий код ничего не выведет:

if (NaN == NaN) alert( "==" ); // Ни один вызов if (NaN === NaN) alert( "===" ); // не сработает

  • Значение NaN можно проверить специальной функцией isNaN(n), которая преобразует аргумент к числу и возвращает true, если получилось NaN, и false – для любого другого значения.

var n = 0 / 0; alert( isNaN(n) ); // true alert( isNaN("12") ); // false, строка преобразовалась к обычному числу 12

  • Значение NaN «прилипчиво». Любая операция с NaN возвращает NaN.

alert( NaN + 1 ); // NaN

Если аргумент isNaN – не число, то он автоматически преобразуется к числу.

Математические операции в JS безопасны. Никакие математические операции в JavaScript не могут привести к ошибке или «обрушить» программу. В худшем случае результат будет NaN.

isFinite(n)

Итак, в JavaScript есть обычные числа и три специальных числовых значения: NaN, Infinity и ‐Infinity.

Тот факт, что они, хоть и особые, но числа, демонстрируется работой оператора +:

var value = prompt("Введите Infinity", 'Infinity');

var number = +value;

alert( number ); // Infinity, плюс преобразовал строку "Infinity" к такому "числу"

Обычно если мы хотим от посетителя получить число, то Infinity или NaN нам не подходят. Для того чтобы отличить «обычные» числа от таких специальных значений, существует функция isFinite.

Функция isFinite(n) преобразует аргумент к числу и возвращает true, если это не NaN/Infinity/‐Infinity:

alert( isFinite(1) ); // true

alert( isFinite(Infinity) ); // false

alert( isFinite(NaN) ); // false

Преобразование к числу

Большинство арифметических операций и математических функций преобразуют значение в число автоматически.

Для того чтобы сделать это явно, обычно перед значением ставят унарный плюс '+':

var num = ‘12.34’;

alert (+num); //12.34

При этом, если строка не является в точности числом, то результат будет NaN:

alert( +"12test" ); // NaN

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

alert( +" ‐12" ); // ‐12

alert( +" \n34 \n" ); // 34, перевод строки \n является пробельным символом

alert( +"" ); // 0, пустая строка становится нулем

alert( +"1 2" ); // NaN, пробел посередине числа ‐ ошибка

Аналогичным образом происходит преобразование и в других математических операторах и функциях:

alert( '12.34' / "‐2" ); // ‐6.17

Мягкое преобразование: parseInt и parseFloat

В мире HTML/CSS многие значения не являются в точности числами. Например метрики CSS: 10pt или‐ 12px.

Оператор '+' для таких значений возвращает NaN:

alert(+"12px") // NaN

Для удобного чтения таких значений существует функция parseInt:

alert( parseInt('12px') ); // 12

Функция parseInt также позволяет указать систему счисления, то есть считывать числа, заданные в шестнадцатиричной и других системах счисления:

alert( parseInt('FF', 16) ); // 255

Проверка на число isNan()

Для проверки строки на число можно использовать функцию isNaN(str).

Она преобразует строку в число аналогично +, а затем вернет true, если это NaN, то есть если преобразование не удалось:

var x = prompt("Введите значение", "‐11.5");

if (isNaN(x)) {

alert( "Строка преобразовалась в NaN. Не число" );

} else {

alert( "Число" );

}

Однако, у такой проверки есть две особенности:

  1. Пустая строка и строка из пробельных символов преобразуются к 0, поэтому считаются числами.

  2. Если применить такую проверку не к строке, то могут быть сюрпризы, в частности isNaN посчитает числами значения false, true, null, так как они хотя и не числа, но преобразуются к ним.

alert( isNaN(null) ); // false ‐ не NaN, т.е. "число"

alert( isNaN("\n \n") ); // false ‐ не NaN, т.е. "число" Если такое поведение допустимо, то isNaN – приемлемый вариант.

Если же нужна действительно точная проверка на число, которая не считает числом строку из пробелов, логические и специальные значения, а также отсекает Infinity – используйте следующую функцию isNumeric:

function isNumeric(n) {

return !isNaN(parseFloat(n)) && isFinite(n);

}

toString(система счисления)

Как показано выше, числа можно записывать не только в 10-ричной, но и в 16-ричной системе. Но бывает и противоположная задача: получить 16-ричное представление числа. Для этого используется метод toString(основание системы), например:

var n = 255;

alert( n.toString(16) ); // ff

num.toFixed(precision)

Существует также специальный метод num.toFixed(precision), который округляет число num до точности precision и возвращает результат в виде строки:

var n = 12.34;

alert( n.toFixed(1) ); // "12.3"

Строки

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

var text = "моя строка";

var anotherText = 'еще строка';

var str = "012345";

В JavaScript нет разницы между двойными и одинарными кавычками.

Специальные символы

Строки могут содержать специальные символы. Самый часто используемый из таких символов – это «перевод строки».

Он обозначается как \n, например:

alert( 'Привет\nМир' ); // выведет "Мир" на новой строке

Есть и более редкие символы, вот их список тык.

Экранирование специальных символов

Если строка в одинарных кавычках, то внутренние одинарные кавычки внутри должны быть экранированы, то есть снабжены обратным слешем ', вот так:

var str = 'I'm a JavaScript programmer';

В двойных кавычках – экранируются внутренние двойные:

var str = "I'm a JavaScript "programmer" ";

alert( str ); // I'm a JavaScript "programmer"

Методы и свойства

Длина length

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

var str = "My\n"; // 3 символа. Третий ‐ перевод строки

alert( str.length ); // 3

Доступ к символам

Чтобы получить символ, используйте вызов charAt(позиция). Первый символ имеет позицию 0:

var str = "jQuery";

alert( str.charAt(0) ); // "j"

В JavaScript нет отдельного типа «символ», так что charAt возвращает строку, состоящую из выбранного символа.

Также для доступа к символу можно также использовать квадратные скобки:

var str = "Я ‐ современный браузер!";

alert( str[0] ); // "Я"

Разница между этим способом и charAt заключается в том, что если символа нет – charAt выдает пустую строку, а скобки – undefined.

Смена регистра

Методы toLowerCase() и toUpperCase() меняют регистр строки на нижний/верхний:

alert( "Интерфейс".toUpperCase() ); // ИНТЕРФЕЙС

Пример ниже получает первый символ и приводит его к нижнему регистру:

alert( "Интерфейс" [0].toLowerCase() ); // 'и'

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

Объекты как ассоциативные массивы

Объекты в JavaScript сочетают в себе два важных функционала.

Первый – это ассоциативный массив: структура, пригодная для хранения любых данных.

Второй – языковые возможности для объектно-ориентированного программирования.

**Ассоциативные массивы **

Ассоциативный массив – структура данных, в которой можно хранить любые данные в формате ключ- значение.

Её можно легко представить как шкаф с подписанными ящиками. Все данные хранятся в ящичках. По имени можно легко найти ящик и взять то значение, которое в нём лежит.

image alt text

Создание объектов

Пустой объект («пустой шкаф») может быть создан одним из двух синтаксисов:

  1. o = new Object();

  2. o = {}; // пустые фигурные скобки

Обычно все пользуются синтаксисом (2), т.к. он короче.

Операции с объектом

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

Например, создадим объект person для хранения информации о человеке:

let person = {}; // пока пустой

image alt text

Основные операции с объектами – это создание, получение и удаление свойств.

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

// при присвоении свойства в объекте автоматически создаётся "ящик"

// с именем "name" и в него записывается содержимое 'Вася'

person.name = 'Вася';

person.age = 25; // запишем ещё одно свойство: с именем 'age' и значением 25

image alt text

Значения хранятся «внутри» ящиков. Обратим внимание – любые значения, любых типов: число, строка – не важно.

Чтобы прочитать их – также обратимся через точку:

console.log( person.name + ': ' + person.age ); // "Вася: 25"

Удаление осуществляется оператором delete:

delete person.age;

Осталось только свойство name:

image alt text

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

Для этого есть особый оператор: "in".

Его синтаксис: "prop" in obj, причем имя свойства – в виде строки, например:

if ("name" in person) {

console.log( "Свойство name существует!" );

}

Впрочем, чаще используется другой способ – сравнение значения с undefined.

Дело в том, что в JavaScript можно обратиться к любому свойству объекта, даже если его нет.

Ошибки не будет. Но если свойство не существует, то вернется специальное значение undefined:

let person = {};

console.log( person.lalala ); // undefined, нет свойства с ключом lalala

Таким образом мы можем легко проверить существование свойства – получив его и сравнив с undefined:

let person = {

name: "Василий"

};

console.log( person.lalala === undefined ); // true, свойства нет

console.log( person.name === undefined ); // false, свойство есть

Доступ через квадратные скобки

Существует альтернативный синтаксис работы со свойствами, использующий квадратные скобки объект['свойство']:

let person = {};

person[] = 'Вася'; // то же что и person.name = 'Вася'

Записи person['name'] и person.name идентичны, но квадратные скобки позволяют использовать в качестве имени свойства любую строку:

let person = {};

person['любимый стиль музыки'] = 'Джаз';

Такое присвоение было бы невозможно «через точку», так интерпретатор после первого пробела подумает, что свойство закончилось, и далее выдаст ошибку:

person.любимый стиль музыки = 'Джаз'; // ошибка

В обоих случаях, имя свойства обязано быть строкой. Если использовано значение другого типа – JavaScript приведет его к строке автоматически.

Доступ к свойству через переменную

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

let person = {};

person.age = 25;

let key = 'age';

console.log( person[key] ); // выведет person['age']

Вообще, если имя свойства хранится в переменной (var key = "age"), то единственный способ к нему обратиться – это квадратные скобки person[key].

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

Объявление со свойствами

Объект можно заполнить значениями при создании, указав их в фигурных скобках: { ключ1: значение1, ключ2: значение2, ... }.

Такой синтаксис называется литеральным (англ. literal).

Следующие два фрагмента кода создают одинаковый объект:

let menuSetup = {

width: 300,

height: 200,

title: "Menu"

};

// то же самое, что:

let menuSetup = {};

menuSetup.width = 300;

menuSetup.height = 200;

menuSetup.title = 'Menu';

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

Например:

let menuSetup = {

width: 300,

'height': 200,

"мама мыла раму": true

};

В качестве значения можно тут же указать и другой объект:

let user = {

name: "Таня",

age: 25,

size: {

top: 90, 

middle: 60, 

bottom: 90 

}

}

console.log(user.name) // "Таня"

console.log(user.size.top) // 90

Здесь значением свойства size является объект {top: 90, middle: 60, bottom: 90 }.

Объекты : перебор свойств

Для перебора всех свойств из объекта используется цикл по свойствам for..in. Эта синтаксическая конструкция отличается от рассмотренного ранее цикла for(;;).

for..in

Синтаксис:

for (key in obj) {

/* ... делать что‐то с obj[key] ... */

}

При этом for..in последовательно переберёт свойства объекта obj, имя каждого свойства будет записано в key и вызвано тело цикла.

Вспомогательную переменную key можно объявить прямо в цикле:

for (let key in menu) {

  // ...

}

Так иногда пишут для краткости кода. Можно использовать и любое другое название, кроме key, например for(let propName in menu).

Пример итерации по свойствам:

let menu = {

width: 300,

height: 200,

title: "Menu"

};

for (let key in menu) {

// вызывается для каждого свойства объекта

alert( "Ключ: " + key + " значение: " + menu[key] );

}

Обратите внимание, мы использовали квадратные скобки menu[key]. Как уже говорилось, если имя свойства хранится в переменной, то обратиться к нему можно только так, не через точку.

Количество свойств в объекте

Как узнать, сколько свойств хранит объект?

Готового метода для этого нет.

Самый кросс-браузерный способ – это сделать цикл по свойствам и посчитать, вот так:

let menu = {

width: 300,

height: 200,

title: "Menu"

};

let counter = 0;

for (let key in menu) {

counter++;

}

console.log( "Всего свойств: " + counter );

Объекты: передача по ссылке

Фундаментальным отличием объектов от примитивов, является их хранение и копирование «по ссылке».

Копирование по значению

Обычные значения: строки, числа, булевы значения, null/undefined при присваивании переменных копируются целиком или, как говорят, «по значению».

let message = "Привет";

let phrase = message;

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

image alt text

Копирование по ссылке

С объектами – всё не так.

В переменной, которой присвоен объект, хранится не сам объект, а «адрес его места в памяти», иными словами – «ссылка» на него.

Вот как выглядит переменная, которой присвоен объект:

let user = {

name: "Вася"

};

image alt text

Внимание: объект – вне переменной. В переменной – лишь «адрес» (ссылка) для него.

При копировании переменной с объектом – копируется эта ссылка, а объект по-прежнему остается в единственном экземпляре.

Пример:

let user = { name: "Вася" }; // в переменной ‐ ссылка

let admin = user; // скопировали ссылку

Получили две переменные, в которых находятся ссылки на один и тот же объект:

image alt text

Так как объект всего один, то изменения через любую переменную видны в других переменных:

let user = { name: 'Вася' };

let admin = user;

admin.name = 'Петя'; // поменяли данные через admin

console.log(user.name); // 'Петя', изменения видны в user

Клонирование объектов

Иногда, на практике – очень редко, нужно скопировать объект целиком, создать именно полную независимую копию, «клон» объекта.

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

let user = {

name: "Вася",

age: 30

};

let clone = {}; // новый пустой объект

// скопируем в него все свойства user

for (var key in user) {

clone[key] = user[key];

}

// теперь clone ‐ полностью независимая копия

clone.name = "Петя"; // поменяли данные в clone

alert( user.name ); // по‐прежнему "Вася"

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

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

Вывод в консоли

Откройте консоль браузера (обычно F12 ) и запустите следующий код:

let time = {

year: 2345,

month: 11,

day: 10,

hour: 11,

minute: 12,

second: 13,

microsecond: 123456

}

console.log(time); // (*)

time.microsecond++; // (**)

console.log(time);

time.microsecond++;

console.log(time);

time.microsecond++;

Как видно, в нём некий объект выводится строкой (*), затем он меняется в строке (**) и снова выводится, и так несколько раз.

Пока ничего необычного, типичная ситуация – скрипт делает какую-то работу с объектом и выводит в консоли то, как она продвигается.

Необычное – в другом!

При раскрытии каждый объект будет выглядеть примерно так (скриншот из Chrome):

image alt text

Судя по выводу, свойство microsecond всегда было равно 123459... Или нет?

Если посмотреть на код выше то, очевидно, нет! Это свойство меняется, а консоль нас просто дурит.

При «раскрытии» свойств объекта в консоли – браузер всегда выводит их текущие (на момент раскрытия) значения.

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

//todo: format array section

Массивы с числовыми индексами

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

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

Объявление

Синтаксис для создания нового массива – квадратные скобки со списком элементов внутри.

Пустой массив:

var arr = []; //синтаксис массива - квадратные скобки.

Массив fruits с тремя элементами:

var fruits = ["Яблоко", "Апельсин", "Слива"];

Элементы нумеруются, начиная с нуля

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

var fruits = ["Яблоко", "Апельсин", "Слива"];

alert( fruits[0] ); // Яблоко

alert( fruits[1] ); // Апельсин

alert( fruits[2] ); // Слива

Элемент можно всегда заменить:

fruits[2] = 'Груша'; // теперь ["Яблоко", "Апельсин", "Груша"];

...Или добавить:

fruits[3] = 'Лимон'; // теперь ["Яблоко", "Апельсин", "Груша", "Лимон"];

Общее число элементов, хранимых в массиве, содержится в его свойстве length:

var fruits = ["Яблоко", "Апельсин", "Груша"];

alert( fruits.length ); // 3

Через alert можно вывести и массив целиком.

При этом его элементы будут перечислены через запятую:

var fruits = ["Яблоко", "Апельсин", "Груша"];

alert( fruits ); // Яблоко,Апельсин,Груша

В массиве может храниться любое число элементов любого типа.

В том числе, строки, числа, объекты, вот например:

// микс значений

var arr = [ 1, 'Имя', { name: 'Петя' }, true ];

// получить объект из массива и тут же ‐‐ его свойство

alert( arr[2].name ); // Петя

Методы pop/push, shift/unshift

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

image alt text

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

Очень близка к очереди еще одна структура данных:* стек *. Это такая коллекция элементов, в которой новые элементы добавляются в конец и берутся с конца.

image alt text

Например, стеком является колода карт, в которую новые карты кладутся сверху, и берутся – тоже сверху.

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

Конец массива

pop()

Удаляет *последний *элемент из массива и возвращает его:

var fruits = ["Яблоко", "Апельсин", "Груша"];

alert( fruits.pop() ); // удалили "Груша"

alert( fruits ); // Яблоко, Апельсин

push()

Добавляет элемент в конец массива:

var fruits = ["Яблоко", "Апельсин"];

fruits.push("Груша");

alert( fruits ); // Яблоко, Апельсин, Груша

Вызов fruits.push(...) равнозначен fruits[fruits.length] = ....

Начало массива

shift()

Удаляет из массива первый элемент и возвращает его:

var fruits = ["Яблоко", "Апельсин", "Груша"];

alert( fruits.shift() ); // удалили Яблоко

alert( fruits ); // Апельсин, Груша

unshift()

Добавляет элемент в начало массива:

var fruits = ["Апельсин", "Груша"];

fruits.unshift('Яблоко');

alert( fruits ); // Яблоко, Апельсин, Груша

Методы push и unshift могут добавлять сразу по несколько элементов:

var fruits = ["Яблоко"];

fruits.push("Апельсин", "Персик");

fruits.unshift("Ананас", "Лимон");

// результат: ["Ананас", "Лимон", "Яблоко", "Апельсин", "Персик"]

alert( fruits );

Внутреннее устройство массива

Массив – это объект, где в качестве ключей выбраны цифры, с дополнительными методами и свойством length.

Так как это объект, то в функцию он передаётся по ссылке:

function eat(arr) {

arr.pop();

}

var arr = ["нам", "не", "страшен", "серый", "волк"];

alert( arr.length ); // 5

eat(arr);

eat(arr);

alert( arr.length ); // 3, в функцию массив не скопирован, а передана ссылка

Ещё одно следствие – можно присваивать в массив любые свойства.

Например:

var fruits = []; // создать массив

fruits[99999] = 5; // присвоить свойство с любым номером

fruits.age = 25; // назначить свойство со строковым именем

... Но массивы для того и придуманы в JavaScript, чтобы удобно работать именно с упорядоченными, нумерованными данными. Для этого в них существуют специальные методы и свойство length.

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

Влияние на быстродействие

Методы push/pop выполняются быстро, а shift/unshift – медленно.

image alt text

Чтобы понять, почему работать с концом массива – быстрее, чем с его началом, разберём подробнее происходящее при операции:

fruits.shift(); // убрать 1 элемент с начала

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

Операция shift должна выполнить целых три действия:

  1. Удалить нулевой элемент.

  2. Переместить все свойства влево, с индекса 1 на 0, с 2 на 1 и так далее.

  3. Обновить свойство length.

image alt text

Чем больше элементов в массиве, тем дольше их перемещать, это много операций с памятью.

Аналогично работает unshift: чтобы добавить элемент в начало массива, нужно сначала перенести вправо, в увеличенные индексы, все существующие.

А что же с push/pop? Им как раз перемещать ничего не надо. Для того, чтобы удалить элемент, метод pop очищает ячейку и укорачивает length.

Действия при операции:

fruits.pop(); // убрать 1 элемент с конца

image alt text

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

Аналогично работает push.

Перебор элементов

Для перебора элементов обычно используется цикл:

var arr = [‘Яблоко’, ‘Апельсин’, ‘Груша’];

for (var i = 0; i < arr.length; i++) {

console.log(arr[i]);

}

Особенности работы length

Встроенные методы для работы с массивом автоматически обновляют его длину length.

Так уж оно устроено.

Это легко увидеть на следующем примере:

var arr = [];

arr[1000] = true;

alert(arr.length); //

Кстати, если у вас элементы массива нумеруются случайно или с большими пропусками, то стоит подумать о том, чтобы использовать обычный объект. Массивы предназначены именно для работы с непрерывной упорядоченной коллекцией элементов.

Используем length для укорачивания массива

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

При уменьшении length массив укорачивается.

Причем этот процесс необратимый, т.е. даже если потом вернуть length обратно – значения не восстановятся:

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

arr.length = 2; // укоротить до 2 элементов

alert( arr ); // [1, 2]

arr.length = 5; // вернуть length обратно, как было

alert( arr[3] ); // undefined: значения не вернулись

Самый простой способ очистить массив – это arr.length=0.

Создание вызовом new Array

new Array()

Существует еще один синтаксис для создания массива:

var arr = new Array("Яблоко", "Груша", "и т.п.");

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

Кроме того, у него есть одна особенность. Обычно n**ew Array(элементы, ...) создаёт массив из данных элементов, но если у него один аргумент - число new Array(число), то он создает массив без элементов, но с заданной длиной.

var arr = new Array(2, 3);

console.log( arr[0] ); // 2, создан массив [2, 3], всё ок

arr = new Array(5); // создаст массив [5] ?

console.log(arr[5]); //undifined! Массив без элементов, длины 5

Что же такое этот «массив без элементов, но с длиной»? Как такое возможно?

Оказывается, очень даже возможно и соответствует объекту {length: 2}. Получившийся массив ведёт себя так, как будто его элементы равны undefined.

Это может быть неожиданным сюрпризом, поэтому обычно используют квадратные скобки.

Многомерные массивы

Массивы в JavaScript могут содержать в качестве элементов другие массивы. Это можно использовать для создания многомерных массивов, например матриц:

var matrix = [

[1, 2, 3],

[4, 5, 6],

[7, 8, 9]

];

console.log( matrix[1][1] ); // центральный элемент (5)

Итого

Массивы существуют для работы с упорядоченным набором элементов.

**Объявление : **

// предпочтительное

var arr = [элемент1, элемент2...];

// new Array

var arr = new Array(элемент1, элемент2...);

При этом new Array(число) создаёт массив заданной длины, без элементов. Чтобы избежать ошибок, предпочтителен первый синтаксис.

Свойство length – длина массива. Если точнее, то последний индекс массива плюс 1. Если её уменьшить вручную, то массив укоротится. Если length больше реального количества элементов, то отсутствующие элементы равны undefined.

Операции с концом массива:

  • arr.push(элемент1, элемент2, …) // добавляет элементы в конец

  • var elem = arr.pop(); // удаляет и возвращает последний эл-т.

**Операции с началом массива: **

  • arr.unshift(элемент1, элемент2...) добавляет элементы в начало.

  • var elem = arr.shift() удаляет и возвращает первый элемент.

Эти операции перенумеровывают все элементы, поэтому работают медленно.

В следующей главе мы рассмотрим другие методы для работы с массивами.

Псевдомассив аргументов "arguments"

В JavaScript любая функция может быть вызвана с произвольным количеством аргументов :

function go(a,b) {

alert("a="+ a +", b="+b);

}

go(1); // a=1, b=undefined

go(1,2); // a=1, b=2

go(1,2,3); // a=1, b=2, третий аргумент не вызовет ошибку

В JavaScript нет «перегрузки» функций.

Доступ к «лишним» аргументам

Как получить значения аргументов, которых нет в списке параметров?

Доступ к ним осуществляется через «псевдо-массив» arguments.

Он содержит список аргументов по номерам: arguments[0], arguments[1]..., а также свойство length. Например, выведем список всех аргументов:

function sayHi() {

	for (var i = 0; i < arguments.length; i++) {

  alert( "Привет, " + arguments[i] );

}

}

sayHi("Винни", "Пятачок"); // 'Привет, Винни', 'Привет, Пятачок'

Все параметры находятся в arguments, даже если они есть в списке. Код выше сработал бы также, будь функция объявлена sayHi(a,b,c).

arguments – это не массив

Частая ошибка новичков – попытка применить методы Array к arguments. Это невозможно:

function sayHi() {

var a = arguments.shift(); // ошибка! нет такого метода!

}

sayHi(1);

Дело в том, что arguments – это не массив Array.

В действительности, это обычный объект, просто ключи числовые и есть length. На этом сходство заканчивается.

Никаких особых методов у него нет, и методы массивов он тоже не поддерживает. Впрочем, никто не мешает сделать обычный массив из arguments, например так:

var args = [];

for (var i = 0; i < arguments.length; i++) {

args[i] = arguments[i];

}

Такие объекты иногда называют «коллекциями» или «псевдомассивами».

Пример : копирование свойств

Аргументы по умолчанию через ||

Если функция вызвана с меньшим количеством аргументов, чем указано, то отсутствующие аргументы считаются равными undefined.

Зачастую в случае отсутствия аргумента мы хотим присвоить ему некоторое «стандартное» значение или, иначе говоря, значение «по умолчанию». Это можно удобно сделать при помощи оператора логическое ИЛИ ||.

Например, функция showWarning, описанная ниже, должна показывать предупреждение. Для этого она принимает ширину width, высоту height, заголовок title и содержимое contents, но большая часть этих аргументов необязательна:

function showWarning(width, height, title, contents) {

width = width || 200; // если не указана width, то width = 200

height = height || 100; // если нет height, то height = 100

title = title || "Предупреждение";

}

Это отлично работает в тех ситуациях, когда «нормальное» значение параметра в логическом контексте отлично от false. В коде выше, при передаче width = 0 или width = null, оператор ИЛИ заменит его на значение по умолчанию.

А что, если мы хотим использовать значение по умолчанию только если width === undefined? В этом случае оператор ИЛИ уже не подойдёт, нужно поставить явную проверку:

function showWarning(width, height, title, contents) {

if (width === undefined) width = 200;

if (height === undefined) height = 100;

if (title === undefined) title = "Предупреждение";

}

Устаревшее свойство arguments.callee

«Именованные аргументы»

Именованные аргументы – альтернативная техника работы с аргументами, которая вообще не использует arguments.

Некоторые языки программирования позволяют передать параметры как-то так: f(width=100, height=200), то есть по именам, а что не передано, тех аргументов нет. Это очень удобно в тех случаях, когда аргументов много, сложно запомнить их порядок и большинство вообще не надо передавать, по умолчанию подойдёт.

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

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

Получается так:

function showWarning(options) {

var width = options.width || 200; // по умолчанию

var height = options.height || 100;

var contents = options.contents || "Предупреждение";

// ...

}

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

showWarning({

contents: "Вы вызвали функцию" // и всё понятно!

});

Сравним это с передачей аргументов через список:

showWarning(null, null, "Предупреждение!");

Не правда ли, объект – гораздо проще и понятнее?

Еще один бонус кроме красивой записи – возможность повторного использования объекта аргументов:

var opts = {

width: 400,

height: 200,

contents: "Текст"

};

showWarning(opts);

opts.contents = "Другой текст";

showWarning(opts); // вызвать с новым текстом, без копирования других аргументов

Именованные аргументы применяются во многих JavaScript-фреймворках.

Итого

  • Полный список аргументов, с которыми вызвана функция, доступен через arguments.

  • Это псевдомассив, то есть объект, который похож на массив, в нём есть нумерованные свойства и length, но методов массива у него нет.

  • В старом стандарте было свойство arguments.callee со ссылкой на текущую функцию, а также свойство arguments.callee.caller, содержащее ссылку на функцию, которая вызвала данную. Эти свойства устарели, при use strict обращение к ним приведёт к ошибке.

  • Для указания аргументов по умолчанию, в тех случаях, когда они заведомо не false, удобен оператор ||.

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

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

function showMessage(text, options) {

// показать сообщение text, настройки показа указаны в options

}

Дата и Время

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

Создание

Для создания нового объекта типа Date используется один из синтаксисов:

new Date()

Создает объект Date с текущей датой и временем:

var now = new Date();

alert( now );

new Date(milliseconds)

Создает объект Date, значение которого равно количеству миллисекунд (1/1000 секунды), прошедших с 1 января 1970 года GMT+0.

// 24 часа после 01.01.1970 GMT+0

var Jan02_1970 = new Date(3600 * 24 * 1000);

alert( Jan02_1970 );

new Date(datestring)

Если единственный аргумент – строка, используется вызов Date.parse (см. далее) для чтения даты из неё.

new Date(year, month, date, hours, minutes, seconds, ms)

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

Заметим:

  • Год year должен быть из 4 цифр.

  • Отсчет месяцев month начинается с нуля 0.

Например:

new Date(2011, 0, 1, 0, 0, 0, 0); // // 1 января 2011, 00:00:00

new Date(2011, 0, 1); // то же самое, часы/секунды по умолчанию равны 0

Дата задана с точностью до миллисекунд:

var date = new Date(2011, 0, 1, 2, 3, 4, 567);

alert( date ); // 1.01.2011, 02:03:04.567

Получение компонентов даты

Для доступа к компонентам даты-времени объекта Date используются следующие методы:

getFullYear()

Получить год (из 4 цифр)

**getMonth() **

Получить месяц, от 0 до 11.

getDate()

Получить число месяца, от 1 до 31.

getHours(), getMinutes(), getSeconds(), getMilliseconds()

Получить соответствующие компоненты.

Дополнительно можно получить день недели:

getDay()

Получить номер дня в неделе. Неделя в JavaScript начинается с воскресенья, так что результат будет числом от 0(воскресенье) до 6(суббота).

Все методы, указанные выше, возвращают результат для местной временной зоны.

getTime()

Возвращает число миллисекунд, прошедших с 1 января 1970 года GMT+0, то есть того же вида, который используется в конструкторе new Date(milliseconds).

getTimezoneOffset()

Возвращает разницу между местным и UTC-временем, в минутах.

alert( new Date().getTimezoneOffset() ); // Для GMT‐1 выведет 60

Установка компонентов даты

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

  • setFullYear(year [, month, date])

  • setMonth(month [, date])

  • setDate(date)

  • setHours(hour [, min, sec, ms])

  • setMinutes(min [, sec, ms])

  • setSeconds(sec [, ms])

  • setMilliseconds(ms)

  • setTime(milliseconds)(устанавливает всю дату по миллисекундам с 01.01.1970 UTC)

Все они, кроме setTime(), обладают также UTC-вариантом, например: setUTCHours().

Как видно, некоторые методы могут устанавливать несколько компонентов даты одновременно, в частности, setHours. При этом если какая-то компонента не указана, она не меняется.

Например:

var today = new Date;

today.setHours(0);

alert( today ); // сегодня, но час изменён на 0

today.setHours(0, 0, 0, 0);

alert( today ); // сегодня, ровно 00:00:00.

Более подробное описание темы Дата и Время тут.

Замыкания, область видимости

image alt text

Понимание «области видимости» и «замыканий» – ключевое в изучении JavaScript, без них «каши не сваришь».

В этом разделе мы более глубоко изучаем переменные и функции – и замыкания в том числе.

Глобальный объект

Глобальными называют переменные и функции, которые не находятся внутри какой-то функции. То есть, иными словами, если переменная или функция не находятся внутри конструкции function, то они – «глобальные»

В JavaScript все глобальные переменные и функции являются свойствами специального объекта, который называется «глобальный объект» (global object).

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

В других окружениях, например Node.JS, глобальный объект может быть недоступен в явном виде, но суть происходящего от этого не изменяется, поэтому далее для обозначения глобального объекта мы будем использовать "window".

Присваивая или читая глобальную переменную, мы, фактически, работаем со свойствами window. (или с объектом global, если выполнение происходит в контексте среды Node.js, например).

Например:

let a = 5; // объявление var создаёт свойство window.a

console.log( window.a ); // 5

Создать переменную можно и явным присваиванием в window:

window.a = 5;

console.log( a ); // 5

Порядок инициализации

Выполнение JS кода происходит в две фазы:

  1. На первой фазе происходит инициализация, подготовка к запуску.

Во время инициализации скрипт сканируется на предмет объявления функций вида Function Declaration, а затем – на предмет объявления переменных. Каждое такое объявление добавляется в window.

**Функции, объявленные как Function Declaration, создаются сразу работающими, а переменные – равными undefined. **

  1. На второй фазе – собственно, выполнение.

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

В коде ниже указано содержание глобального объекта на момент инициализации и далее последовательно по коду:

// На момент инициализации, до выполнения кода:

// window = { f: function, a: undefined, g: undefined }

**let a = 5; **

// window = { f: function, a: 5, g: undefined }

**function f(arg) { /.../ } **

// window = { f: function, a: 5, g: undefined } без изменений, f обработана ранее

**valetr g = function(arg) { /.../ }; **

// window = { f: function, a: 5, g: function }

Кстати, тот факт, что к началу выполнения кода переменные и функции уже содержатся в window, можно легко проверить, выведя их:

alert("a" in window); // true, т.к. есть свойство window.a

console.log(a); // равно undefined, присваивание будет выполнено далее

console.log(f); // function ..., готовая к выполнению функция

console.log(g); // undefined, т.к. это переменная, а не Function Declaration

**let a = 5; **

**function f() { /.../ } **

let g = function() { /.../ };

Конструкции for, if... не влияют на видимость переменных

Фигурные скобки, которые используются в for, while, if, в отличие от объявлений функции, имеют «декоративный» характер.

В JavaScript нет разницы между объявлением вне блока:

*let i; *

*{ *

  • i = 5; *

}

...И внутри него:

*i = 5; *

*{ *

  • *
    

}

Также нет разницы между объявлением в цикле и вне его:

  •    *
    

for (let i = 0; i < 5; i++) { }

Идентичный по функциональности код:

  •  *
    

*let i; *

for (i = 0; i < 5; i++) { }

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

Итого

В результате инициализации, к началу выполнения кода:

  1. Функции, объявленные как Function Declaration, создаются полностью и готовы к использованию.

  2. Переменные объявлены, но равны undefined. Присваивания выполнятся позже, когда выполнение дойдет до них.

Замыкания, функции изнутри

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

Лексическое окружение

Все переменные внутри функции – это свойства специального внутреннего объекта LexicalEnvironment, который создаётся при её запуске.

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

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

В отличие от window, объект LexicalEnvironment является внутренним, он скрыт от прямого доступа.

Для того чтобы лучше понимать как это работает, посмотрим пример:

function sayHi(name) {

let phrase = "Привет, " + name;

console.log( phrase );

}

sayHi('Вася');

При вызове функции:

  1. До выполнения первой строчки её кода, на стадии инициализации, интерпретатор создает пустой объект LexicalEnvironment и заполняет его.

function sayHi(name) {

// LexicalEnvironment = {name: 'Вася', phrase: undefined}

let phrase = "Привет, " + name;

console.log( phrase );

}

sayHi(‘Вася’);

  1. Функция выполняется.

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

function sayHi(name) {

// LexicalEnvironment = { name: 'Вася', phrase: undefined }

let phrase = "Привет, " + name; 

// LexicalEnvironment = { name: 'Вася', phrase: 'Привет, Вася'}

console.log( phrase );

}

sayHi('Вася');

  1. В конце выполнения функции объект с переменными обычно выбрасывается и память очищается. В примерах выше так и происходит. Через некоторое время мы рассмотрим более сложные ситуации, при которых объект с переменными сохраняется и после завершения функции.

Доступ ко внешним переменным

Из функции мы можем обратиться не только к локальной переменной, но и к внешней:

var userName = "Вася";

function sayHi() {

console.log( userName ); // "Вася"

}

Интерпретатор, при доступе к переменной, сначала пытается найти переменную в текущем LexicalEnvironment, а затем, если её нет – ищет во внешнем объекте переменных. В данном случае им является window.

Такой порядок поиска возможен благодаря тому, что ссылка на внешний объект переменных хранится в специальном внутреннем свойстве функции, которое называется [[Scope]]. Это свойство закрыто от прямого доступа, но знание о нём очень важно для понимания того, как работает JavaScript.

При создании функция получает скрытое свойство [[Scope]], которое ссылается на лексическое окружение, в котором она была создана.

В примере выше таким окружением является window, так что создаётся свойство:

sayHi.[[Scope]] = window

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

При запуске функции её объект переменных LexicalEnvironment получает ссылку на «внешнее лексическое окружение» со значением из [[Scope]].

Если переменная не найдена в функции – она будет искаться снаружи.

Именно благодаря этой механике в примере выше console.log(userName) выводит внешнюю переменную. На уровне кода это выглядит как поиск во внешней области видимости, вне функции.

Если обобщить:

  • Каждая функция при создании получает ссылку [[Scope]] на объект с переменными, в контексте которого была создана.

  • При запуске функции создаётся новый объект с переменными LexicalEnvironment. Он получает ссылку на внешний объект переменных из [[Scope]].

  • При поиске переменных он осуществляется сначала в текущем объекте переменных, а потом – по этой ссылке.

Выглядит настолько просто, что непонятно – зачем вообще говорить об этом [[Scope]], об объектах переменных. Сказали бы: «Функция читает переменные снаружи» – и всё. Но знание этих деталей позволит нам легко объяснить и понять более сложные ситуации, с которыми мы столкнемся далее.

Всегда текущее значение

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

Например, в коде ниже функция sayHi берёт phrase из внешней области:

var phrase = 'Привет';

function sayHi(name) {

alert(phrase + ', ' + name);

}

sayHi('Вася'); // Привет, Вася (*)

phrase = 'Пока';

sayHi('Вася'); // Пока, Вася (**)

На момент первого запуска (*), переменная phrase имела значение 'Привет', а ко второму (**) изменила его на 'Пока'.

Это естественно, ведь для доступа к внешней переменной функция по ссылке [[Scope]] обращается во внешний объект переменных и берёт то значение, которое там есть на момент обращения.

Вложенные функции

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

К примеру, вложенная функция может помочь лучше организовать код:

function sayHiBye(firstName, lastName) {

console.log( "Привет, " + getFullName() );

console.log( "Пока, " + getFullName() );

function getFullName() {

return firstName + " " + lastName; 

}

}

sayHiBye("Вася", "Пупкин"); // Привет, Вася Пупкин ; Пока, Вася Пупкин

Здесь, для удобства, создана вспомогательная функция getFullName().

Вложенные функции получают [[Scope]] так же, как и глобальные. В нашем случае:

getFullName.[[Scope]] = объект переменных текущего запуска sayHiBye

Благодаря этому getFullName() получает снаружи firstName и lastName.

Заметим, что если переменная не найдена во внешнем объекте переменных, то она ищется в ещё более внешнем (через [[Scope]] внешней функции), то есть, такой пример тоже будет работать:

let phrase = 'Привет';

function say() {

function go() {

console.log( phrase ); // найдёт переменную снаружи 

}

go();

}

say();

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

Рассмотрим более «продвинутый» вариант, при котором внутри одной функции создаётся другая и возвращается в качестве результата.

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

Здесь мы будем создавать функцию-счётчик, которая считает свои вызовы и возвращает их текущее число.

В примере ниже makeCounter создает такую функцию:

function makeCounter() {

let count = 1;

return function(){

return currentCount++; 

};

}

let counter = makeCounter();

// каждый вызов увеличивает счётчик и возвращает результат

console.log( counter() ); // 1

console.log( counter() ); // 2

console.log( counter() ); // 3

// создать другой счетчик, он будет независим от первого

let counter2 = makeCounter();

console.log(counter2() ); // 1

Как видно, мы получили два независимых счетчика counter и counter2, каждый из которых незаметным снаружи образом сохраняет текущее количество вызовов.

Где? Конечно, во внешней переменной currentCount, которая у каждого счётчика своя.

Если подробнее описать происходящее:

  1. В строке (*) запускается makeCounter(). При этом создаётся LexicalEnvironment для переменных текущего вызова. В функции есть одна переменная var currentCount, которая станет свойством этого объекта. Она изначально инициализуется в undefined, затем, в процессе выполнения, получит значение 1:

function makeCounter() { // LexicalEnvironment = { currentCount: undefined } let currentCount = 1; // LexicalEnvironment = { currentCount: 1 } return function() { // [[Scope]] ‐> LexicalEnvironment (**) return currentCount++; }; }

let counter = makeCounter(); // (*)

  1. В процессе выполнения makeCounter() создаёт функцию в строке (**). При создании эта функция получает внутреннее свойство [[Scope]] со ссылкой на текущий LexicalEnvironment.

  2. Далее вызов makeCounter() завершается и функция (**) возвращается и сохраняется во внешней переменной counter (*).

На этом создание «счётчика» завершено.

Итоговым значением, записанным в переменную counter, является функция:

function() { // [[Scope]] ‐> {currentCount: 1}

return currentCount++;

};

Возвращённая из makeCounter() функция counter помнит (через [[Scope]]) о том, в каком окружении была создана.

Это и используется для хранения текущего значения счётчика.

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

Эта функция состоит из одной строки: return currentCount++, ни переменных ни параметров в ней нет, поэтому её собственный объект переменных, для краткости назовём его LE – будет пуст.

Однако, у неё есть свойство [[Scope]], которое указывает на внешнее окружение. Чтобы увеличить и вернуть currentCount, интерпретатор ищет в текущем объекте переменных LE, не находит, затем идёт во внешний объект, там находит, изменяет и возвращает новое значение:

function makeCounter() {

var currentCount = 1;

return function() {

return currentCount++; 

};

}

var counter = makeCounter(); // [[Scope]] ‐> {currentCount: 1}

alert( counter() ); // 1, [[Scope]] ‐> {currentCount: 1}

alert( counter() ); // 2, [[Scope]] ‐> {currentCount: 2}

alert( counter() ); // 3, [[Scope]] ‐> {currentCount: 3}

Переменную во внешней области видимости можно не только читать, но и изменять.

В примере выше было создано несколько счётчиков. Все они взаимно независимы:

var counter = makeCounter();

var counter2 = makeCounter();

alert( counter() ); // 1

alert( counter() ); // 2

alert( counter() ); // 3

alert( counter2() ); // 1, счётчики независимы

Они независимы, потому что при каждом запуске makeCounter создаётся свой объект переменных LexicalEnvironment, со своим свойством currentCount, на который новый счётчик получит ссылку [[Scope]].

Свойства функции

Функция в JavaScript является объектом, поэтому можно присваивать свойства прямо к ней, вот так:

function f() {}

f.test = 5;

alert( f.test );

Свойства функции не стоит путать с переменными и параметрами. Они совершенно никак не связаны. Переменные доступны только внутри функции, они создаются в процессе её выполнения. Это – использование функции «как функции».

А свойство у функции – доступно отовсюду и всегда. Это – использование функции «как объекта».

Если хочется привязать значение к функции, то можно им воспользоваться вместо внешних переменных.

В качестве демонстрации, перепишем пример со счётчиком:

function makeCounter() {

function counter() {

return counter.currentCount++;

};

counter.currentCount = 1;

	return counter;

}

var counter = makeCounter();

alert( counter() ); // 1

alert( counter() ); // 2

При запуске пример работает также.

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

Например, можно взять и поменять счётчик из внешнего кода:

var counter = makeCounter();

alert( counter() ); // 1

counter.currentCount = 5;

alert( counter() ); // 5

Итого: замыкания

Замыкание – это функция вместе со всеми внешними переменными, которые ей доступны.

Таково стандартное определение, которое есть в Wikipedia и большинстве серьёзных источников по программированию. То есть, замыкание – это функция + внешние переменные.

Тем не менее, в JavaScript есть небольшая терминологическая особенность.

Обычно, говоря «замыкание функции», подразумевают не саму эту функцию, а именно внешние переменные.

Иногда говорят «переменная берётся из замыкания». Это означает – из внешнего объекта переменных.

Что это такое–«понимать замыкания?»

Иногда говорят «Вася молодец, понимает замыкания!». Что это такое – «понимать замыкания», какой смысл обычно вкладывают в эти слова?

«Понимать замыкания» в JavaScript означает понимать следующие вещи:

  1. Все переменные и параметры функций являются свойствами объекта переменных LexicalEnvironment. Каждый запуск функции создает новый такой объект. На верхнем уровне им является «глобальный объект», в браузере – window.

  2. При создании функция получает системное свойство [[Scope]], которое ссылается на LexicalEnvironment, в котором она была создана.

  3. При вызове функции, куда бы её ни передали в коде – она будет искать переменные сначала у себя, а затем во внешних LexicalEnvironment с места своего «рождения».

Цепочки областей видимости : https://youtu.be/MQD4_v8oc0**k **

Замыкания : **https://youtu.be/rpIxGwFz0X**s

Ключевое слово THIS

Оригинал : https://habr.com/ru/company/ruvds/blog/419371/

Тем, кто хочет изучить JavaScript, в любом случае придётся разобраться с this.

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

Контекст всегда является значением ключевого слова this, которое ссылается на объект, «владеющий» кодом, выполняемым в текущий момент. Однако, тот контекст, который имеет отношение к this, это не то же самое, что контекст выполнения.

Ситуации, когда this указывает на объект window

Если вы попытаетесь обратиться к ключевому слову this в глобальной области видимости, оно будет привязано к глобальному контексту, то есть — к объекту window в браузере.

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

console.log(this);

// в консоль выводится объект Window

// Window { postMessage: ƒ,

// blur: ƒ,

// focus: ƒ,

// close: ƒ,

// frames: Window, …}

function myFunction() {

console.log(this);

}

// Вызовем функцию

myFunction();

// функция выводит тот же объект Window!

// Window { postMessage: ƒ,

// blur: ƒ,

// focus: ƒ,

// close: ƒ,

// frames: Window, …}

Использование this внутри объекта

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

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

let dog = {

name: 'Chester',

breed: 'beagle',

intro: function(){

console.log(this);

}

};

dog.intro();

// в консоль выводится представление объекта dog со всеми его свойствами и методами

// {name: "Chester", breed: "beagle", intro: ƒ}

// breed:"beagle"

// intro:ƒ ()

// name:"Chester"

// proto:Object

This и вложенные объекты

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

var obj1 = {

hello: function() {

console.log('Hello world');

return this;

},

obj2: {

  breed: 'dog',

  speak: function(){

        console.log('woof!');

        return this;

    }

}

};

console.log(obj1);

console.log(obj1.hello()); // выводит 'Hello world' и возвращает obj1

console.log(obj1.obj2);

console.log(obj1.obj2.speak()); // выводит 'woof!' и возвращает obj2

Особенности стрелочных функций

Стрелочные функции ведут себя не так, как обычные функции. Вспомните: при обращении к this в методе объекта, этому ключевому слову соответствует объект, которому принадлежит метод. Однако это не относится к стрелочным функциям. Вместо этого, this в таких функциях относится к глобальному контексту (к объекту window). Рассмотрим следующий код, который можно запустить в консоли браузера.

var objReg = {

hello: function() {

return this;

}

};

var objArrow = {

hello: () => this

};

objReg.hello(); // возвращает, как и ожидается, объект objReg

objArrow.hello(); // возвращает объект Window!

Использование this в обычных функциях

Когда обычная функция находится в глобальной области видимости, то ключевое слово this, использованное в ней, будет привязано к объекту window. Ниже приведён пример, в котором функцию test можно рассматривать в виде метода объекта window.

function test() {

console.log('hello world');

console.log(this);

}

test();

// hello world

// Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}

Обращение к this из функции, которая была объявлена за пределами объекта, а потом назначена в качестве его метода

Рассмотрим пример с уже известным нам объектом dog. В качестве метода этого объекта можно назначить функцию chase, объявленную за его пределами. Тут в объекте dog никаких методов не было, до тех пор, пока мы не создали метод foo, которому назначена функция chase.

Если теперь вызвать метод dog.foo, то будет вызвана функция chase. При этом ключевое слово this, к которому обращаются в этой функции, указывает на объект dog. А функция chase, при попытке её вызова как самостоятельной функции, будет вести себя неправильно, так как при таком подходе this будет указывать на глобальный объект, в котором нет тех свойств, к которым мы, в этой функции, обращаемся через this.

let dog = {

breed: 'Beagles',

lovesToChase: 'rabbits'

};

function chase() {

console.log(this.breed + ' loves chasing ' + this.lovesToChase + '.');

}

dog.foo = chase();

dog.foo(); // в консоль попадёт Beagles loves chasing rabbits.

chase(); //так эту функцию лучше не вызывать

Ключевое слово new и this

Ключевое слово this находит применение в функциях-конструкторах, используемых для создания объектов, так как оно позволяет, универсальным образом, работать со множеством объектов, создаваемых с помощью такой функции. В JavaScript есть и стандартные функции-конструкторы, с помощью которых, например, можно создавать объекты типа Number или String. Подобные функции, определяемые программистом самостоятельно, позволяют ему создавать объекты, состав свойств и методов которых задаётся им самим.

function Dog(breed, name, friends){

this.breed = breed;

this.name = name;

this.friends = friends;	

this.intro = function() {

    console.log(`Hi, my name is ${this.name} and I’m a ${this.breed}`);

    return this;

}; 

}

Когда функцию-конструктор вызывают с использованием ключевого слова new, this в ней указывает на новый объект, который, с помощью конструктора, снабжают свойствами и методами.

Вот как можно работать со стандартными конструкторами JavaScript.

var str = new String('Hello world');

/*******

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

*******/

var str2 = 'Hello world';

// когда строка объявлена так, система, всё равно, позволяет работать с ней как с объектом

Теперь поработаем с только что созданной функцией-конструктором Dog.

// Создадим новый экземпляр объекта типа Dog

let chester = new Dog('beagle', 'Chester', ['Gracie', 'Josey', 'Barkley']);

chester.intro();// выводит Hi, my name is Chester and I'm a beagle

console.log(chester);// выводит Dog {breed: "beagle", name: "Chester", friends: Array(3), intro: ƒ}

О важности ключевого слова new

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

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

// Функция-конструктор

var Friend = function(name, password, interests, job){

this.fullName = name;

this.password = password;

this.interests = interests;

this.job = job;

};

function sayHello(){

// раскомментируйте следующую строчку, чтобы узнать, на что указывает this

// console.log(this);

return Hi, my name is ${this.fullName} and I'm a ${this.job}. Let's be friends!;

}

// Мы можем создать один или несколько экземпляров объекта типа Friend, используя ключевое слово new

var john = new Friend('John Smith', 'badpassword', ['hiking', 'biking', 'skiing'], 'teacher');

console.log(john);

// Назначим функцию ключу greeting объекта john

john.greeting = sayHello;

// Вызовем новый метод объекта

console.log( john.greeting() );

// Помните о том, что sayHello() не стоит вызывать как обычную функцию

console.log( sayHello() ) ;

Итого

Особенности использования ключевого слова this в JavaScript не ограничиваются вышеописанными примерами. Так, в череду этих примеров можно было бы включить использование функций call, apply и bind.

https://learn.javascript.ru/constructor-new

**Bind, call, apply **

Создадим простой объект, чтобы использовать его в качестве контекста

let obj = {

foo: "bar"

};

Функция, которая возвращает свойство «foo» контекста «this»

function returnFoo() {

return this.foo;

}

Свойства не существует в текущей области видимости, поэтому undefined

returnFoo(); // => undefined

Но если мы свяжем эту функцию с контекстом

let bound = returnFoo.bind(obj);

Свойство теперь в области видимости

bound(); // => "bar"

Так работает Function.prototype.bind.

Так как returnFoo — это функция, она наследует прототип Function.prototype

Существует несколько способов связывания функции с контекстом

Call и apply позволяют вам вызывать функцию с нужным контекстом

returnFoo.call(obj); // => bar

returnFoo.apply(context); // => bar

Так же можно вложить функцию в объект

context.returnFoo = returnFoo;

context.returnFoo(); // => bar

Теперь давайте немного усложним.

В Array.prototype есть замечательный метод slice.

При вызове на массиве он возвращает копию массива от начального индекса до конечного (исключительно)

[1,2,3].slice(0,1); // => [1]

Мы берем slice и присваиваем его локальной переменной

let slice = Array.prototype.slice;

slice теперь оторван от контекста. Из-за того, что Array.prototype.slice

работает с данным ему контекстом «this», метод больше не работает

slice(0, 1); // => TypeError: can't convert undefined to object

slice([1,2,3], 0, 1); // => TypeError: ...

Но мы можем использовать apply и call, они позволяют нам передавать нужный контекст

slice.call([1,2,3], 0, 1); // => [1]

Apply работает как call, но принимает аргументы в виде массива

slice.apply([1,2,3], [0,1]); // => [1]

Немного надоедает использовать .call каждый раз. Может воспользоваться bind?

Давайте привяжем функцию call к контексту slice:

slice = Function.prototype.call.bind(Array.prototype.slice);

Теперь slice использует первый аргумент в качестве контекста

slice([1,2,3], 0, 1); // => [1]

Неплохо, правда? Но у меня осталась еще кое-что

Давайте проделаем с самим bind то же, что мы делали со slice:

let bind = Function.prototype.call.bind(Function.prototype.bind);

Обдумайте то, что мы только что сделали.

Что происходит? Мы оборачиваем call, возвращая функцию, которая принимает функцию и контекст и возвращает связанную с контекстом функцию.

Вернемся к нашему первоначальному примеру

var context = { foo: "bar" };

function returnFoo () {

return this.foo;

}

И к нашему новому bind

var amazing = bind(returnFoo, context);

amazing(); // => bar

Оригинал: https://habr.com/ru/post/199456/

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind

DOM, BOM

image alt text

Сам по себе язык JavaScript не предусматривает работы с браузером.

Он вообще не знает про HTML. Но позволяет легко расширять себя новыми функциями и объектами.

На рисунке ниже схематически отображена структура, которая получается если посмотреть на совокупность браузерных объектов с «высоты птичьего полёта».

image alt text

Как видно из рисунка, на вершине стоит window.

У этого объекта двоякая позиция – он с одной стороны является глобальным объектом в JavaScript, с другой – содержит свойства и методы для управления окном браузера, открытия новых окон, например:

window.open('https://myfreedom.by/courses');

Объект window реализует интерфейс Window, который наследуется от интерфейса AbstractView. Некоторые дополнительные глобальные функции, пространства имен объектов, интерфейсы и конструкторы, как правило, не связанные с окном, но доступные в нем, перечислены в JavaScript ссылки и DOM ссылки.

Объектная модель документа (DOM)

Объект document является свойством объекта window. Даёт возможность взаимодействовать с содержимым страницы.

Пример использования:

document.body.style.background = 'red';

Возвращаем в обратно :

document.body.style.background = '';

Он и громадное количество его свойств и методов описаны в стандарте W3C DOM.

По историческим причинам когда-то появилась первая версия стандарта DOM Level 1, затем придумали ещё свойства и методы, и появился DOM Level 2, на текущий момент поверх них добавили ещё DOM Level 3 и готовится DOM 4.

Объектная модель браузера (BOM)

BOM – это объекты для работы с чем угодно, кроме документа.

Например:

  • Объект navigator содержит общую информацию о браузере и операционной системе. Особенно примечательны два свойства: navigator.userAgent – содержит информацию о браузере и navigator.platform – содержит информацию о платформе, позволяет различать Windows/Linux/Mac и т.п.

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

  • Функции alert/confirm/prompt – тоже входят в BOM.

Большинство возможностей BOM стандартизированы в HTML 5, хотя различные браузеры и предоставляют зачастую что-то своё, в дополнение к стандарту.

Дерево DOM

Основным инструментом работы и динамических изменений на странице является DOM (Document Object Model) – объектная модель, используемая для XML/HTML-документов.

Согласно DOM-модели, документ является иерархией, деревом. Каждый HTML-тег образует узел дерева с типом «элемент». Вложенные в него теги становятся дочерними узлами. Для представления текста создаются узлы с типом «текст».

DOM – это представление документа в виде дерева объектов, доступное для изменения через JavaScript.

Построим, для начала, дерево DOM для следующего документа.

<title>О лосях</title>

Правда о лосях

В этом дереве выделено два типа узлов.

Теги образуют узлы-элементы (element node). Естественным образом одни узлы вложены в другие. Структура дерева образована исключительно за счет них.

Текст внутри элементов образует текстовые узлы (text node), обозначенные как #text. Текстовый узел содержит исключительно строку текста и не может иметь потомков, то есть он всегда на самом нижнем уровне.

Обратите внимание на специальные символы в текстовых узлах:

  • перевод строки: ↵

  • пробел: ␣

Пробелы и переводы строки – это тоже текст, полноправные символы, которые учитываются в DOM.

В частности, в примере выше тег содержит не только узлы-элементы и , но и #text (пробелы, переводы строки) между ними.

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

В остальных случаях всё честно – если пробелы есть в документе, то они есть и в DOM, а если их убрать, то и в DOM их не будет, получится так:

Автоисправление

При чтении неверного HTML браузер автоматически корректирует его для показа и при построении DOM.

В частности, всегда будет верхний тег . Даже если в тексте нет – в DOM он будет, браузер создаст его самостоятельно.

То же самое касается и тега .

Например, если файл состоит из одного слова "Привет", то браузер автоматически обернёт его в и .

При генерации DOM браузер самостоятельно обрабатывает ошибки в документе, закрывает теги и так далее.

Такой документ:

Привет

  • Мама
  • и
  • Папа

    …Превратится во вполне респектабельный DOM, браузер сам закроет теги.

    <p>Привет</p>
    
  • Мама
  • и
  • Папа
  • Другие типы узлов

    Дополним страницу новыми тегами и комментарием:

    Правда о лосях

      <li>Лось — животное хитрое</li>
      
      <!-- комментарий -->
      
      <li>...и коварное!</li>
      

    В этом примере тегов уже больше, и даже появился узел нового типа – комментарий.

    Казалось бы, зачем комментарий в DOM? На отображение-то он всё равно не влияет. Но так как он есть в HTML – обязан присутствовать в DOM-дереве.

    Всё, что есть в HTML, находится и в DOM.

    Даже директива <!DOCTYPE...>, которую мы ставим в начале HTML, тоже является DOM-узлом, и находится в дереве DOM непосредственно перед .

    Даже сам объект document, формально, является DOM-узлом, самым-самым корневым.

    Всего различают 12 типов узлов, но на практике мы работаем с четырьмя из них:

    1. Документ – точка входа в DOM.

    2. Элементы – основные строительные блоки.

    3. Текстовые узлы – содержат, собственно, текст.

    4. Комментарии – иногда в них можно включить информацию, которая не будет показана, но доступна из JS.

    Возможности, которые дает DOM

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

    Узел HTML можно получить как document.documentElement, а BODY – как document.body.

    Получив узел, мы можем что-то сделать с ним.

    Например, можно поменять цвет BODY и вернуть обратно:

    document.body.style.backgroundColor = 'red';

    console.log( 'Поменяли цвет BODY' );

    document.body.style.backgroundColor = '';

    console.log( 'Сбросили цвет BODY' );

    DOM предоставляет возможность делать со страницей всё, что угодно.

    Позже мы более подробно рассмотрим различные свойства и методы DOM-узлов.

    Итого

    • DOM-модель – это внутреннее представление HTML-страницы в виде дерева.

    • Все элементы страницы, включая теги, текст, комментарии, являются узлами DOM.

    • У элементов DOM есть свойства и методы, которые позволяют изменять их.

    • IE8- не генерирует пробельные узлы.

    Кстати, DOM-модель используется не только в JavaScript, это известный способ представления XML-документов.

    Навигация по DOM-элементам

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

    Доступ к DOM начинается с объекта document. Из него можно добраться до любых узлов.

    Так выглядят основные ссылки, по которым можно переходить между узлами DOM:

    image alt text

    Посмотрим на них повнимательнее.

    documentElement и body

    Самые верхние элементы дерева доступны напрямую из document.

    = document.documentElement

    Первая точка входа – document.documentElement. Это свойство ссылается на DOM-объект для тега .

    = document.body

    Вторая точка входа – document.body, который соответствует тегу .

    Дети: childNodes, firstChild, lastChild

    Здесь и далее мы будем использовать два принципиально разных термина.

    • Дочерние элементы (или дети) – элементы, которые лежат непосредственно внутри данного. Например, внутри обычно лежат и .

    • Потомки – все элементы, которые лежат внутри данного, вместе с их детьми, детьми их детей и так далее. То есть, всё поддерево DOM.

    Псевдо-массив childNodes хранит все дочерние элементы, включая текстовые.

    Пример ниже последовательно выведет дочерние элементы document.body:

    Начало
      <li>Информация</li>
      
    Конец
    <script> for (var i = 0; i < document.body.childNodes.length; i++) { alert( document.body.childNodes[i] ); // Text, DIV, Text, UL, ..., SCRIPT } </script>

    ...

    Обратим внимание на маленькую деталь. Если запустить пример выше, то последним будет выведен элемент <script>. На самом-то деле в документе есть ещё текст (обозначенный троеточием), но на момент выполнения скрипта браузер ещё до него не дошёл.

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

    Скажем больше – все навигационные свойства, которые перечислены в этой главе – только для чтения. Нельзя просто заменить элемент присвоением childNodes[i] = ....

    Изменение DOM осуществляется другими методами, которые мы рассмотрим далее, все навигационные ссылки при этом обновляются автоматически.

    Свойства firstChild и lastChild обеспечивают быстрый доступ к первому и последнему элементу.

    При наличии дочерних узлов всегда верно:

    elem.childNodes[0] === elem.firstChild

    elem.childNodes[elem.childNodes.length - 1] === elem.lastChild

    Коллекции – не массивы

    DOM-коллекции, такие как childNodes и другие, которые мы увидим далее, не являются JavaScript-массивами.

    В них нет методов массивов, таких как forEach, map, push, pop и других.

    let elems = document.documentElement.childNodes;

    elems.forEach(function(elem) { // нет такого метода!

    /* ... */

    });

    Именно поэтому childNodes и называют «коллекция» или «псевдомассив».

    Можно для перебора коллекции использовать обычный цикл for(var i=0; i<elems.length; i++)

    Соседи и родитель

    Доступ к элементам слева и справа данного можно получить по ссылкам previousSibling / nextSibling.

    Родитель доступен через parentNode. Если долго идти от одного элемента к другому, то рано или поздно дойдёшь до корня DOM, то есть до document.documentElement, а затем и document.

    Навигация только по элементам

    Навигационные ссылки, описанные выше, равно касаются всех узлов в документе. В частности, в childNodes сосуществуют и текстовые узлы и узлы-элементы и узлы-комментарии, если есть.

    Но для большинства задач текстовые узлы нам не интересны.

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

    image alt text

    Эти ссылки похожи на те, что раньше, только в ряде мест стоит слово Element:

    • children – только дочерние узлы-элементы, то есть соответствующие тегам.

    • firstElementChild, lastElementChild – соответственно, первый и последний дети-элементы.

    • previousElementSibling, nextElementSibling – соседи-элементы.

    • parentElement – родитель-элемент.

    Модифицируем предыдущий пример, применив children вместо childNodes.

    Теперь он будет выводить не все узлы, а только узлы-элементы:

    Начало
      <li>Информация</li>
      
    Конец
    <script> for (var i = 0; i < document.body.children.length; i++) { alert( document.body.children[i] ); // DIV, UL, DIV, SCRIPT } </script>

    ...

    Всегда верны равенства:

    elem.firstElementChild === elem.children[0]

    elem.lastElementChild === elem.children[elem.children.length - 1]

    Итого

    В DOM доступна навигация по соседним узлам через ссылки:

    • По любым узлам.

    • Только по элементам.

    Поиск: getElement, querySelector, другие**

    Прямая навигация от родителя к потомку удобна, если элементы рядом. А если нет?

    Как достать произвольный элемент откуда-то из глубины документа?

    Для этого в DOM есть дополнительные методы поиска.

    document.getElementById или просто id

    Если элементу назначен специальный атрибут id, то можно получить его прямо по переменной с именем из значения id.

    О****бщепринятой практикой является доступ к элементу вызовом document.getElementById("идентификатор").

    Например:

    Выделим этот элемент
    <script> var elem = document.getElementById('content'); elem.style.background = 'red'; </script>

    getElementsByTagName

    Метод elem.getElementsByTagName(tag) ищет все элементы с заданным тегом tag внутри элемента elem и возвращает их в виде списка.

    Регистр тега не имеет значения.

    Например:

    // получить все div-элементы

    var elements = document.getElementsByTagName('div');

    Обратим внимание: в отличие от getElementById, который существует только в контексте document, метод getElementsByTagName может искать внутри любого элемента.

    <td>Ваш возраст:</td>
    
    <td>
    
      <label>
    
        <input type="radio" name="age" value="young" checked> младше 18
    
      </label>
    
      <label>
    
        <input type="radio" name="age" value="mature"> от 18 до 50
    
      </label>
    
      <label>
    
        <input type="radio" name="age" value="senior"> старше 60
    
      </label>
    
    </td>
    
    <script> var tableElem = document.getElementById('age-table'); var elements = tableElem.getElementsByTagName('input'); for (var i = 0; i < elements.length; i++) { var input = elements[i]; alert( input.value + ': ' + input.checked ); } </script>

    Можно получить всех потомков, передав звездочку '*' вместо тега:

    // получить все элементы документа

    document.getElementsByTagName('*');

    // получить всех потомков элемента elem:

    elem.getElementsByTagName('*');

    Не забываем про букву "s"!

    Одна из самых частых ошибок начинающих (впрочем, иногда и не только) – это забыть букву "s", то есть пробовать вызывать метод getElementByTagName вместо getElementsByTagName.

    Буква "s" не нужна там, где элемент только один, то есть в getElementById, в остальных методах она обязательна.

    Возвращается коллекция, а не элемент

    Другая частая ошибка – это код вида:

    // не работает

    document.getElementsByTagName('input').value = 5;

    То есть, вместо элемента присваивают значение коллекции. Работать такое не будет.

    Коллекцию нужно или перебрать в цикле или получить элемент по номеру и уже ему присваивать value, например так:

    // работает

    document.getElementsByTagName('input')[0].value = 5;

    document.getElementsByName

    Вызов document.getElementsByName(name) позволяет получить все элементы с данным атрибутом name.

    Например, все элементы с именем age:

    let elems = document.getElementsByName('age');

    Используется этот метод весьма редко.

    getElementsByClassName

    Вызов elem.getElementsByClassName(className) возвращает коллекцию элементов с классом className. Находит элемент и в том случае, если у него несколько классов, а искомый – один из них.

    Поддерживается всеми современными браузерами, кроме IE8-.

    Например:

    Статья
    Длинная статья
    <script> let articles = document.getElementsByClassName('article'); alert( articles.length ); // 2, найдёт оба элемента </script>

    Как и getElementsByTagName, этот метод может быть вызван и в контексте DOM-элемента, и в контексте документа.

    querySelectorAll

    Вызов elem.querySelectorAll(css) возвращает все элементы внутри elem, удовлетворяющие CSS-селектору css.

    Это один из самых часто используемых и полезных методов при работе с DOM.

    Он есть во всех современных браузерах, включая IE8+ (в режиме соответствия стандарту).

    Следующий запрос получает все элементы li, которые являются последними потомками в ul:

    • Этот
    • тест
    • полностью
    • пройден
    <script> var elements = document.querySelectorAll('ul > li:last-child'); for (var i = 0; i < elements.length; i++) { alert( elements[i].innerHTML ); // "тест", "пройден" } </script>

    Псевдо-класс тоже работает

    Псевдо-классы в CSS-селекторе, в частности :hover и :active, также поддерживаются. Например, document.querySelectorAll(':hover') вернёт список, в порядке вложенности, из текущих элементов под курсором мыши.

    querySelector

    Вызов elem.querySelector(css) возвращает не все, а только первый элемент, соответствующий CSS-селектору css.

    Иначе говоря, результат – такой же, как и при elem.querySelectorAll(css)[0], но в последнем вызове сначала ищутся все элементы, а потом берётся первый, а в elem.querySelector(css) ищется только первый, то есть он эффективнее.

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

    matches

    Предыдущие методы искали по DOM.

    Метод elem.matches(css) ничего не ищет, а проверяет, удовлетворяет ли elem селектору css. Он возвращает true либо false.

    Не поддерживается в IE8-.

    Этот метод бывает полезным, когда мы перебираем элементы (в массиве или по обычным навигационным ссылкам) и пытаемся отфильтровать те из них, которые нам интересны.

    Ранее в спецификации он назывался matchesSelector, и большинство браузеров поддерживают его под этим старым именем, либо с префиксами ms/moz/webkit.

    Например:

    ...

    ...

    <script> var elems = document.body.children; for (var i = 0; i < elems.length; i++) { if (elems[i].matches('a[href$="zip"]')) { alert( "Ссылка на архив: " + elems[i].href ); } } </script>

    closest

    Метод elem.closest(css) ищет ближайший элемент выше по иерархии DOM, подходящий под CSS-селектор css. Сам элемент тоже включается в поиск.

    Иначе говоря, метод closest бежит от текущего элемента вверх по цепочке родителей и проверяет, подходит ли элемент под указанный CSS-селектор. Если подходит – останавливается и возвращает его.

    Он самый новый из методов, рассмотренных в этой главе, поэтому старые браузеры его слабо поддерживают.

    Пример использования (браузер должен поддерживать closest):

    • Глава I
      <ul>
      
        <li class="subchapter">Глава <span class="num">1.1</span></li>
      
        <li class="subchapter">Глава <span class="num">1.2</span></li>
      
      </ul>
      
    <script> var numberSpan = document.querySelector('.num'); // ближайший элемент сверху подходящий под селектор li alert(numberSpan.closest('li').className) // subchapter // ближайший элемент сверху подходящий под селектор .chapter alert(numberSpan.closest('.chapter').tagName) // LI // ближайший элемент сверху, подходящий под селектор span // это сам numberSpan, так как поиск включает в себя сам элемент alert(numberSpan.closest('span') === numberSpan) // true </script>

    Итого

    Есть 6 основных методов поиска элементов DOM:

    Метод Ищет по... Ищет внутри элемента? Поддержка
    getElementById id - везде
    getElementsByName name - везде
    getElementsByTagName тег или '*' везде
    getElementsByClassName классу кроме IE8-
    querySelector CSS-селектор везде
    querySelectorAll CSS-селектор везде

    Практика показывает, что в 95% ситуаций достаточно querySelector/querySelectorAll. Хотя более специализированные методы getElement* работают чуть быстрее, но разница в миллисекунду-другую редко играет роль.

    Свойства узлов: тип, тег и содержимое

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

    Классы, иерархия DOM

    Самое главное различие между DOM-узлами – разные узлы являются объектами различных классов.

    Поэтому, к примеру, у узла, соответствующего тегу – одни свойства, у

    – другие, у – третьи.

    Есть и кое-что общее, за счет наследования.

    Классы DOM образуют иерархию.

    Основной объект в ней: Node, от которого наследуют остальные:

    image alt text

    На рисунке выше изображены основные классы:

    • Прямо от Node наследуют текстовые узлы Text, комментарии Comment и элементы Element.

    • Элементы Element – это ещё не HTML-элементы, а более общий тип, который используется в том числе в XML. От него наследует SVGElement для SVG-графики и, конечно, HTMLElement.

    • От HTMLElement уже наследуют разнообразные узлы HTML:

    Для – HTMLInputElement

    Для – HTMLBodyElement

    Для – HTMLAnchorElement… и так далее.

    Тип: nodeType

    Тип узла содержится в его свойстве nodeType.

    Как правило, мы работаем всего с двумя типами узлов:

    • Элемент.

    • Текстовый узел.

    Тип узла можно только читать, изменить его невозможно.

    Тег: nodeName и tagName

    Существует целых два свойства: nodeName и tagName, которые содержат название(тег) элемента узла.

    Название HTML-тега всегда находится в верхнем регистре.

    Например, для document.body:

    console.log( document.body.nodeName ); // BODY

    console.log( document.body.tagName ); // BODY

    Свойство tagName есть только у элементов Element (в IE8- также у комментариев, но это ошибка в браузере).

    Свойство nodeName определено для любых узлов Node, для элементов оно равно tagName, а для не-элементов обычно содержит строку с типом узла.

    innerHTML: содержимое элемента

    Свойство innerHTML описано в спецификации HTML 5 – embedded content.

    Оно позволяет получить HTML-содержимое элемента в виде строки. В innerHTML можно и читать и писать.

    Пример выведет на экран все содержимое document.body, а затем заменит его на другое:

    Параграф

    Div
    <script> alert( document.body.innerHTML ); // читаем текущее содержимое document.body.innerHTML = 'Новый BODY!'; // заменяем содержимое </script>

    Значение, возвращаемое innerHTML – всегда валидный HTML-код. При записи можно попробовать записать что угодно, но браузер исправит ошибки:

    <script> document.body.innerHTML = 'тест'; // незакрытый тег alert( document.body.innerHTML ); // тест (исправлено) </script>

    Свойство innerHTML – одно из самых часто используемых.

    outerHTML: HTML элемента целиком

    Свойство outerHTML содержит HTML элемента целиком.

    Пример чтения outerHTML:

    Привет Мир
    <script> var div = document.body.children[0]; alert( div.outerHTML ); //
    Привет Мир
    </script>

    Изменить outerHTML элемента невозможно.

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

    При этом переменная, в которой изначально был старый элемент, и в которой мы «перезаписали» outerHTML, остаётся со старым элементом.

    Это легко может привести к ошибкам, что видно на примере:

    <script> var div = document.body.children[0]; // заменяем div.outerHTML на

    ...

    div.outerHTML = '

    Новый элемент!

    '; // ... но содержимое div.outerHTML осталось тем же, несмотря на "перезапись" alert( div.outerHTML ); //
    Привет, Мир!
    </script>

    То, что произошло в примере выше – так это замена div в документе на новый узел

    ...

    . При этом переменная div не получила этот новый узел! Она сохранила старое значение, чтение из неё это отлично показывает.

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

    Текст: textContent

    Свойство textContent содержит только текст внутри элемента, за вычетом всех <тегов>.

    Оно поддерживается везде, кроме IE8-.

    Например:

    Срочно в номер!

    Марсиане атакуют людей!

    <script> var news = document.body.children[0]; // \n Срочно в номер!\n Марсиане атакуют людей!\n alert( news.textContent ); </script>

    Как видно из примера выше, возвращается в точности весь текст, включая переводы строк и пробелы, но без тегов.

    Иными словами, elem.textContent возвращает конкатенацию всех текстовых узлов внутри elem.

    Не сказать, чтобы эта информация была часто востребована.

    Гораздо полезнее возможность записать текст в элемент, причём именно как текст!

    Исследование элементов

    У DOM-узлов есть и другие свойства, зависящие от типа, например:

    • value – значение для INPUT, SELECT или TEXTAREA

    • id – идентификатор

    • href – адрес ссылки

    • …многие другие…

    Например:

    <script> var input = document.body.children[0]; alert( input.type ); // "text" alert( input.id ); // "elem" alert( input.value ); // значение </script>

    Итого

    Основные свойства DOM-узлов:

    nodeType

    Тип узла. Самые популярные типы: "1" – для элементов и "3" – для текстовых узлов. Только для чтения.

    nodeName/tagName

    Название тега заглавными буквами. nodeName имеет специальные значения для узлов-неэлементов. Только для чтения.

    innerHTML

    Внутреннее содержимое узла-элемента в виде HTML. Можно изменять.

    outerHTML

    Полный HTML узла-элемента. При записи в elem.outerHTML переменная elem сохраняет старый узел.

    textContent

    Содержит только текст внутри элемента, за вычетом всех тегов. Можно использовать для защиты от вставки произвольного HTML кода

    Обзор протокола HTTP

    image alt text

    HTTP (HyperText Transfer Protocol) — это протокол, позволяющий получать различные ресурсы, например HTML-документы. Протокол HTTP лежит в основе обмена данными в Интернете.

    HTTP является протоколом клиент-серверного взаимодействия, что означает инициирование запросов к серверу самим получателем, обычно веб-обзорщиком (web-browser). Полученный итоговый документ будет (может) состоять из различных поддокументов являющихся частью итогового документа: например, из отдельно полученного текста, описания структуры документа, изображений, видео-файлов, скриптов и многого другого.

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

    Хотя HTTP был разработан еще в начале 1990-х годов, за счет своей расширяемости в дальнейшем он все время совершенствовался. HTTP является протоколом прикладного уровня, который чаще всего использует возможности другого протокола - TCP (или TLS - защищённый TCP) - для пересылки своих сообщений, однако любой другой надежный транспортный протокол теоретически может быть использован для доставки таких сообщений. Благодаря своей расширяемости, он используется не только для получения клиентом гипертекстовых документов, изображений и видео, но и для передачи содержимого серверам, например, с помощью HTML-форм. HTTP также может быть использован для получения только частей документа с целью обновления веб-страницы по запросу (например посредством AJAX запроса).

    image alt text

    Составляющие систем, основанных на HTTP

    HTTP — это клиент-серверный протокол, то есть запросы отправляются какой-то одной стороной — участником обмена (user-agent) (либо прокси вместо него).

    Каждый запрос (англ. request) отправляется серверу, который обрабатывает его и возвращает ответ (англ. response). Между этими запросами и ответами как правило существуют многочисленные посредники, называемые прокси, которые выполняют различные операции и работают как шлюзы или кэш, например.

    image alt text

    Обычно между обзорщиком и сервером гораздо больше различных устройств-посредников, которые играют какую-либо роль в обработке запроса: маршрутизаторы, модемы и так далее. Благодаря тому, что Сеть построена на основе системы уровней (слоёв) взаимодействия, эти посредники "спрятаны" на сетевом и транспортном уровнях. В этой системе уровней HTTP занимает самый верхний уровень, который называется "прикладным" (или "уровнем приложений").

    Клиент: участник обмена

    Участник обмена (user agent) — это любой инструмент или устройство, действующие от лица пользователя.

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

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

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

    Веб-сервер

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

    Сервер не обязательно расположен на одной машине, и наоборот - несколько серверов могут быть расположены (хоститься) на одной и той же машине. В соответствии с версией HTTP/1.1 и имея Host заголовок, они даже могут делить тот же самый IP-адрес.

    Прокси

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

    • caching (кеш может быть публичным или приватными, как кеш браузера

    • фильтрация (как сканирование антивируса, родительский контроль, …)

    • выравнивание нагрузки (позволить нескольким серверам обслуживать разные запросы)

    • аутотентификация (контролировать доступом к разным ресурсам)

    • протоколирование (разрешение на хранение истории операций)

    HTTP сообщения

    Существует два типа HTTP сообщений, запросы и ответы, каждый в своем формате.

    Примеры HTTP запросов:

    image alt text

    Запросы содержат следующие элементы:

    • HTTP-метод, обычно глагол подобно GET, POST или существительное, как OPTIONS или HEAD, определяющее операцию, которую клиент хочет выполнить. Обычно, клиент хочет получить ресурс (используя GET) или передать значения HTML-формы (используя POST), хотя другие операция могут быть необходимы в других случаях.

    • Путь к ресурсу: URL ресурсы лишены элементов, которые очевидны из контекста, например без protocol (http://), domain (здесь developer.mozilla.org), или TCP port (здесь 80).

    • Версию HTTP-протокола.

    • Заголовки (опционально), предоставляюшие дополнительную информацию для сервера.

    • Или тело, для некоторых методов, таких как POST, которое содержит отправленный ресурс.

    Примеры ответов:

    image alt text

    Ответы содержат следующие элементы:

    • Версию HTTP-протокола.

    • HTTP код состояния, сообщающий об успешности запроса или причине неудачи.

    • Сообщение состояния -- краткое описание кода состояния.

    • HTTP заголовки, подобно заголовкам в запросах.

    • Опционально: тело, содержащее пересылаемый ресурс.

    Итого

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

    Хотя HTTP/2 добавляет некоторую сложность, встраивая HTTP сообщения во фреймы для улучшения производительности, базовая структура сообщений осталась с HTTP/1.0. Сессионый поток остается простым, позволяя исследовать и отлаживать с простым монитором HTTP-сообщений.

    Асинхронное программирование в JS

    image alt text

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

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

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

    Асинхронный код убирает блокирующую операцию из основного потока программы, так что она продолжает выполняться, но где-то в другом месте, а обработчик может идти дальше. Проще говоря, главный «процесс» ставит задачу и передает ее другому независимому «процессу».

    setTimeout, setInterval

    Основными функциями асинхронного кода JavaScript являются setTimeout и setInterval. Функция setTimeout выполняет заданную функцию после истечения определенного временного интервала. Она принимает возвратную функцию в качестве первого аргумента и время (в миллисекундах) в качестве второго аргумента. Вот пример использования:

    console.log( "a" );

    setTimeout(function() {

    console.log( "c" )

    }, 500 );

    setTimeout(function() {

    console.log( "d" )
    

    }, 500 );

    setTimeout(function() {

    console.log( "e" )
    

    }, 500 );

    console.log( "b" );

    Ожидается, что в консоли мы увидим "a", “b”, а затем через примерно 500 мс - “c”, “d”, и “e”.

    "Примерно" потому, что в действительности setTimeout работает непредсказуемо. Даже в спецификации HTML5 указано: "Таким образом, API не гарантирует, что таймер выполнится точно по заданному расписанию. Вероятны задержки из-за нагрузки процессора, других задач и прочих факторов."

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

    Цикл событий очередь возвратных функций. Когда асинхронная функция выполняется, возвратная функция ставится в очередь. JavaScript не запускает обработку цикла событий, пока код, запущенный после асинхронной функции выполняется. Данный факт означает, что код JavaScript не является многопоточным, хотя и кажется таковым.

    AJAX

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

    Она будет полезна для понимания, что такое AJAX и с чем его едят.

    AJAX (аббревиатура от «Asynchronous Javascript And Xml») – технология обращения к серверу без перезагрузки страницы.

    За счет этого уменьшается время отклика и веб-приложение по интерактивности больше напоминает десктоп.

    Несмотря на то, что в названии технологии присутствует буква X (от слова XML), использовать XML вовсе не обязательно. Под AJAX подразумевают любое общение с сервером без перезагрузки страницы, организованное при помощи JavaScript.

    Элементы интерфейса

    В первую очередь AJAX полезен для форм и кнопок, связанных с элементарными действиями: добавить в корзину, подписаться, и т.п.

    Сейчас – в порядке вещей, что такие действия на сайтах осуществляются без перезагрузки страницы.

    Живой поиск

    Живой поиск – классический пример использования AJAX, взятый на вооружение современными поисковыми системами.

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

    image alt text

    Код, который это обеспечивает, работает следующим образом.

    1. Код активируется примерно при каждом нажатии клавиши, но не чаще чем раз в 100 мс (примерно).

    2. Создается скрытый DIV и заполняется ответом сервера:

    • Текущий результат подсвечен, можно перемещаться и выбирать
    • При нажатии правой стрелки или при клике -- поиск в подрезультатах
    1. Результаты запросов кешируются, повторных обращений к серверу не происходит.

    2. В Google не только предлагаются варианты, но система тут же инициирует и сам поиск, т.е. не нужно даже нажимать key:Enter.

    Технически, с помощью AJAX можно обмениваться любыми данными с сервером.

    • JSON – для отправки и получения структурированных данных, объектов.

    • XML – если сервер почему-то работает в формате XML, то можно использовать и его, есть средства.

    • HTML/текст – можно и просто загрузить с сервера код HTML или текст для показа на странице.

    • Бинарные данные, файлы – гораздо реже, в современных браузерах есть удобные средства для них.

    Основы XMLHttpRequest

    Объект XMLHttpRequest (или, как его кратко называют, «XHR») дает возможность из JavaScript делать HTTP-запросы к серверу без перезагрузки страницы.

    Несмотря на слово «XML» в названии, XMLHttpRequest может работать с любыми данными, а не только с XML.

    Использовать его очень просто.

    Как правило, XMLHttpRequest используют для загрузки данных.

    Для начала посмотрим на пример использования, который загружает файл phones.json из текущей директории и выдаёт его содержимое:

    // 1. Создаём новый объект XMLHttpRequest

    var xhr = new XMLHttpRequest();

    // 2. Конфигурируем его: GET-запрос на URL 'phones.json'

    xhr.open('GET', 'phones.json', false);

    // 3. Отсылаем запрос

    xhr.send();

    // 4. Если код ответа сервера не 200, то это ошибка

    if (xhr.status != 200) {

    // обработать ошибку

    alert( xhr.status + ': ' + xhr.statusText ); // пример вывода: 404: Not Found

    } else {

    // вывести результат

    alert( xhr.responseText ); // responseText -- текст ответа.

    }

    Настроить: open

    xhr.open(method, URL, async, user, password)

    Этот метод – как правило, вызывается первым после создания объекта XMLHttpRequest.

    Задаёт основные параметры запроса:

    • method – HTTP-метод. Как правило, используется GET либо POST, хотя доступны и более экзотические, вроде TRACE/DELETE/PUT и т.п.

    • URL – адрес запроса. Можно использовать не только http/https, но и другие протоколы, например ftp:// и file://.

    При этом есть ограничения безопасности, называемые «Same Origin Policy»: запрос со страницы можно отправлять только на тот же протокол://домен:порт, с которого она пришла. В следующих главах мы рассмотрим, как их можно обойти.

    • async – если установлено в false, то запрос производится синхронно, если true – асинхронно.

    «Синхронный запрос» означает, что после вызова xhr.send() и до ответа сервера главный поток будет «заморожен»: посетитель не сможет взаимодействовать со страницей – прокручивать, нажимать на кнопки и т.п. После получения ответа выполнение продолжится со следующей строки.

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

    • user, password – логин и пароль для HTTP-авторизации, если нужны.

    Заметим, что вызов open, в противоположность своему названию (open – англ. «открыть») не открывает соединение. Он лишь настраивает запрос, а коммуникация инициируется методом send.

    Отослать данные: send

    xhr.send([body])

    Именно этот метод открывает соединение и отправляет запрос на сервер.

    В body находится тело запроса. Не у всякого запроса есть тело, например у GET-запросов тела нет, а у POST – основные данные как раз передаются через body.

    Отмена: abort

    Вызов xhr.abort() прерывает выполнение запроса.

    Ответ: status, statusText, responseText

    Основные свойства, содержащие ответ сервера:

    status

    HTTP-код ответа: 200, 404, 403 и так далее. Может быть также равен 0, если сервер не ответил или при запросе на другой домен.

    statusText

    Текстовое описание статуса от сервера: OK, Not Found, Forbidden и так далее.

    responseText

    Текст ответа сервера.

    Есть и ещё одно свойство, которое используется гораздо реже:

    responseXML

    Если сервер вернул XML, снабдив его правильным заголовком Content-type: text/xml, то браузер создаст из него XML-документ. По нему можно будет делать запросы xhr.responseXml.querySelector("...") и другие.

    Введение в библиотеку jQuery

    image alt text

    jQueryбиблиотека JavaScript, фокусирующаяся на взаимодействии JavaScript и HTML. Библиотека jQuery помогает легко получать доступ к любому элементу DOM, обращаться к атрибутам и содержимому элементов DOM, манипулировать ими. Также библиотека jQuery предоставляет удобный API для работы с AJAX. Сейчас разработка jQuery ведётся командой jQuery во главе с Джоном Резигом.

    ...читать далее на wiki

    История создания и описание библиотеки

    Язык разметки HTML - был первым , что освоил автор библиотеки jQuery Джон Резиг, когда он только начал заниматься программированием. В свое время в подарок от отца, Джон получил две книги по HTML. С тех пор у него появился интерес к веб-разработке и HTML в частности. Однако страсть к JavaScript к нему пришла позже, примерно в 2004 году. В то время Джон работал в местной компании Brand Logic и занимался дизайном сайта. Его беспокоило то что он использует JavaScript код сторонних разработчиков, после чего он решил основательно изучить JavaScript. Изучив, пришёл к выводам, что JavaScript — это простой, но изящный язык, который является невероятно мощным для решения многих задач. В течение следующей пары лет Джон создал множество различных JavaScript-приложений, прежде чем закончить создание jQuery. Основной целью создания jQuery Резиг видел возможность закодировать многоразовые куски кода, которые позволят упростить JavaScript и использовать их так, чтобы не беспокоиться о кросс-браузерных вопросах. Библиотека была представлена общественности на компьютерной конференции «BarCamp» в Нью-Йорке в 2006 году.

    Девиз jQuery - "Пиши меньше, делай больше (Write less, do more)". Все дело в том что с помощью одной строки кода библиотека jQuery позволяет достичь того же результата, что и 100 строк кода исключительно на языке JavaScript.

    Основные достоинства:** **

    • Дружественность веб-дизайнерам. jQuery не подразумевает, что вы являетесь компьютерным гением. Она лишь предлагает, что большинство веб-дизайнеров знакомы с CSS.

    • Испытания и надежность. Библиотека jQuery используется на миллионах сайтов, включая очень популярные с большим трафиком : Pinterest, MSN.com, Amazon, Microsoft.com, Craiglist и т.д. На самом деле данную библиотеку содержит 72% всех сайтов.

    • **Бесплатность **

    • **Большое сообщество разработчиков. **Множество людей работают над проектом jQuery. jQuery проживет долго, потому что поддерживается усилиями программистов со всего мира.

    • Большое количество плагинов. jQuery имеет множество плагинов, помимо самого ядра библиотеки. Они не включаются в него в целях экономии размера библиотеки, но свободно распространяются как и сама библиотека. Например библиотека jQuery UI , которая предоставляет расширенные возможности анимации , эффектов и др.

    Подключение библиотеки

    Для того чтобы скачать jQuery, нужно перейти на соответствующую страницу - http://jquery.com/download/. Выбираем "Download the compressed, production jQuery 3.1.1" (На момент написания, версия 3.1.1 была самой актуальной. Если вы видите другую версию, то наверняка библиотека обновилась и вам нужно получить последнюю версию).

    Далее нам нужно создать пустой проект, файл index.html, положить наш jQuery в папку (либо подпапку js(scripts)), и подключить к нашему index.html внизу страницы, перед закрывающимся тегом body. Проверяйте путь к файлу. Он должен быть указан корректно и относительно расположения текущего index.html.

    ...

    <script src="js/jquery.min.js”></script>

    Далее в папке нашего проекта (либо подпапке js(scripts) нужно создать ваш js файл, в котором мы будем писать наш код. Также подключите его к странице перед закрывающимся тегом body, но после подключения jQuery :

    ...

    <script src="js/jquery.min.js”></script> <script src="js/main.js”></script>

    Все! Библиотека подключена, наш файл main.js создан и подключен. Мы готовы к работе.

    Основы jQuery

    Механизм получения элементов страницы

    Для работы с jQuery, используется функция $(), которая в параметрах принимает DOM элемент и анонимную функцию обратного вызова (callback). Элементами в данном случаем могут быть любые DOM элементы.

    $(селектор, function (){

    });

    Механизм нацеливания на элемент, такой же как и у селекторов css. Например :

    $(document); // получение глобального объекта document

    $(window); // получение глобального объекта window

    Если элементов, подходящих под описание, несколько, то возвращается массив этих элементов. Например :

    $(‘p’) // получим все элементы p

    Для более точного нацеливания, можно применять такие же селекторы доступа , как и в css. Это могут быть :

    • Классы : $(‘.text’);

    • Айдишники : $(‘#submit-button’);

    • Селекторы потомков : $(‘div p a’);

    • Псевдоклассы : $(‘ul li:first-child’);

    • Селекторы атрибутов : $ (‘a[href="www.vk.com”]’);

    • И любые комбинации : $(‘ul > li.second-description a#dropdown-button’)

    Базовые функции jQuery для работы с DOM

    Для получения и/или изменения внутреннего содержимого элемента, используется метод .text().

    Метод — в программировании, функция или процедура, принадлежащая какому-то классу или объекту.

    $(‘.welcome-block’).text(); // вернет текстовое содержимое элемента или пустую строку

    var text = $(‘.welcome-block’).text(); // получаем содержимое и присваиваем его переменной text

    console.log(text); // выводим содержимое переменной на экран

    Через метод .text(), также можно и изменить внутреннее содержимое элемента:

    var name = prompt(‘Введите ваше имя’, ‘ ’); // спросили у пользователя его имя

    $(‘.welcome-block’).text(‘Привет, ’ + name); // Изменили внутреннее содержимое элемента. Теперь .welcome-block содержит текст "Привет, Олег". Старое содержимое удалено.

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

    Допустим имеется кусок HTML кода :

      <li>Диагностика</li>
      
      <li>Обслуживание</li>
      
      <li>Анализ</li>
      

    Вызов:

    $(‘.description-list’).html(); // вернет внутреннее содержимое. В данном случае:

  • Диагностика
  • Обслуживание
  • Анализ
  • Для того чтобы добавить элемент на страницу, можно воспользоваться методом .html() с параметром. При этом добавляется дочерний элемент относительно вызванному элементу. Например :

    $(‘p’).html(‘<a href="gohome.com” target=’_blank’>Вернуться домой’); // В элемент

    будет добавлена ссылка. Весь внутренний HTML будет заменен.

    Для поиска элемента внутри элемента, используется метод .find("парметр"). В парамтрах данного метода нужно указывать селектор доступа. Это может быть класс элемента, айди, любой другой подходящий по выборке.

    Например :

    $(‘.welcome-text’).find(‘.name’); //Вернет элемент, если он находится внутри элемента с классом .welcome-text

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

    Например (представим что .welcome-text находится в header) :

    $(‘.welcome-text’).parent(); // вернет header var body = $(‘.welcome-text’).parent(‘body’); // вернет body

    body

    .welcome-text

    Для получения дочерних всех дочерних элементов, можно использовать метод .children(‘параметр’). При вызове метода без параметров, вернутся все дочерние элементы. При вызове метода с параметрами, вернутся все элементы , подходящие по выборке.

    Вернемся к нашему списку :

      <li>Диагностика</li>
      
      <li>Обслуживание</li>
      
      <li class="active”>Анализ</li>
      

    Вызов :

    $(‘.description-list’).children(); //вернутся все элементы li

    $(‘.description-list’).children(‘.active’); //вернется элемент с классом .active

    Метод .append() добавляет в HTML-код в качестве последнего дочернего элемента выбранного элемента. К примеру, мы выбрали div , но вместо замены и добавления нового содержимого через метод html(), мы просто хотим добавить фрагмент HTML-кода перед закрывающимся тегом . Функция append() - это отличный способ добавить элемент в конец маркированного списка (ul) или нумерованного списка (ol). Допустим мы можем создать список задач и добавлять в него задачи в виде пунктов списка (li).

    В случае когда мы работали с методом .html(), нам нужно было записывать в переменную текущее значение и потом конкатенировать ее с новым элементом.

    Пример :

    HTML:

      <li>Диагностика</li>
      
      <li>Обслуживание</li>
      
      <li class="active”>Анализ</li>
      

    $(‘.description-list’).append(‘

  • Консультация
  • ’); //добавляет элемент в конец списка, при этом не заменяет содержимое.

    Функция .prepend() схожа с функцией .append(), но добавляет HTML-код прямо после открывающегося тега выборки. Пример (возьмем тот же HTML код) :

    $(‘.description-list’).prepend(‘

  • Оценка
  • ’) //элемент появиться сразу после открывающегося тега выборки (‘.description-list’);

    Если мы хотим добавить элемент вне выборки , т.е либо ДО открывающегося тега выбранного элемента, либо ПОСЛЕ закрывающегося тега выбранного элемента - мы используем функции before() или after().

    Пример (тот же HTML код) :

    $(‘.description-list’).before(

    Наши услуги

    ); // Добавит заголовок перед нашим списком . Итоговый код будет выглядеть так :

    Наши услуги

      <li>Диагностика</li>
      
      <li>Обслуживание</li>
      
      <li class="active”>Анализ</li>
      

    $(‘.description-list’).after(<a href="#” class=”order-btn”>Заказать услугу) // Добавит кнопку заказать после нашего списка. Итоговый код будет выглядеть так :

    Наши услуги

      <li>Диагностика</li>
      
      <li>Обслуживание</li>
      
      <li class="active”>Анализ</li>
      

    <a href="#” class=”order-btn”>Заказать услугу

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

      <li>
      
          <span class="task">Написать урок</span>
      
          <button class="remove-btn"></button>
      
      </li>
      
      <li>
      
          <span class="task">Позвонить девушке</span>
      
          <button class="remove-btn"></button>
      
      </li>
      
      <li>
      
          <span class="task">Показать сайт начальству</span>
      
          <button class="remove-btn"></button>
      
      </li>
      
      <li>
      
          <span class="task">Получить новое задание</span>
      
          <button class="remove-btn"></button>
      
      </li>
      
      <li>
      
          <span class="task">Выполнить задание</span>
      
          <button class="remove-btn"></button>
      
      </li>
      

    Допустим после выполнения определенной задачи, я хочу ее удалять кликнув на кнопку с классом remove-btn. Для удаления элемента, нужно использовать функцию .remove() :

    $(‘.task’).remove(); // Данный вызов удалит таск. Проблема только в том что он удалит все элементы с классом .task

    Углубленный jQuery

    image alt text

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

    Установка и чтение атрибутов элемента

    Библиотека jQuery хороша не только в добавлении, удалении и изменении элементов. И это не все действия, которые вы захотите произвести, работая с выборкой элементов. Часто вам понадобится изменить значение атрибута элемента : добавить класс или изменить css свойство.

    Манипуляция классами

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

    Добавление класса к элементу :

    $(‘.elem’).addClass(‘active’); // Добавить класс active к элементу с классом elem

    Удаление класса у элемента:

    $(‘.elem’).removeClass(‘active’); //Удалить класс active у elem

    Применяя функции addClass() и removeClass(), передавайте только имя класса, опуская при этом точку.

    Переключение класса у элемента:

    $(‘.elem’).toggleClass(‘active’); // Если у элемента нету класс active, тогда он добавится, иначе если он есть, то он удалится.

    Чтение и изменение свойств CSS

    jQuery функции css() позволяет добавлять CSS непосредственно к элементу. Не путать с манипуляцией классами, т.к css свойства добавленные с помощью функции css() не взаимодействуют с таблицей стилей.

    Для определения текущего значения CSS передайте имя свойства в функцию css(). Узнаем свойство background-color у элемента main:

    var mainBgColor = $(main).css(‘background-color’); //#fff

    Библиотека jQuery возвращает цвет в rgb значении, а шрифт в пикселях, даже если в вашей таблице стилей он указан в процентах (150%).

    Функция css() также позволяет присваивать элементу css свойство. Для этого передадим функции 2 аргумента : имя свойства и значение. Пример :

    $(main).css(‘font-size’, ‘200%’);

    Второй аргумент может быть строкой, например ‘200%’, или числовым значением, которое jQuery переведет в пикселы. Например изменим внутренний левый отступ у всех параграфов:

    $(p).css(‘padding-left’, 20);

    Также можно использовать сокращения:

    $(p).css(‘border-left’, ‘4px solid #f5f5f5’);

    Еще одно применение функции css(). Допустим, увеличим шрифт для пользователя в 2 раза :

    var currentFontSize = $(body).css(‘font-size’);

    currentFontSize = parseInt(currentFontSize); // получаем целое число

    $(body).css(‘font-size’, currentFontSize * 2);

    В первой строке мы получим строку "16px", из которой мы получаем целое число во второй строке. Далее простая математика.

    Одновременное изменение нескольких свойств CSS

    Ситуации, когда необходимо добавить несколько свойств совершенно обычная. И можно было бы пойти таким путем решения проблемы :

    $(body).css(‘font-size’, 14);

    $(body).css(‘background-color’, ‘#fcfcfc’);

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

    $(body).css({

    ‘font-size’: 14,

    ‘background-color’: ‘#fcfcfc’

    });

    Чтение, установка и удаление атрибутов HTML

    Библиотека jQuery содержит функции общего назначения для работы с атрибутами HTML - функции attr() и removeAttr()

    Получить значение атрибута :

    var pathToImage = $(‘.poster’).attr(‘src’);

    Изменить значение атрибута:

    $(‘.poster’).attr(‘src’, ‘/img/posters/first.png’);

    Удалить атрибут:

    $(‘.poster’).removeAttr(‘title’);

    Как видите, механизм получения / изменения значения идентичен примерам выше. Большинство функций в jQuery работает именно так.

    Работа с каждым элементом выборки

    Уникальным свойством библиотеки jQuery является то, что большинство функций автоматически прорабатывают в цикле каждый элемент выборки. Например, чтобы на странице исчезли все элементы img, нужна всего лишь одна строка кода JavaScript:

    $(img).fadeOut();

    Функция fadeOut() заставляет элемент медленно исчезать. Прикрепив данную функцию к выборке jquery, содержащей несколько элементов, функция прорабатывает выборку в цикле и заставляет медленно исчезать каждый ее элемент. Во многих случаях вам понадобится перебрать серию элементов и с каждым из них выполнить определенное действие - функцию. Именно для этих целей jQuery предлагает функцию .each().

    Функция each() принимает анонимную функцию, в теле которой будет наш код. Вот пример:

    <img class="poster” data-desc=”Постер-наклейка ‘Арктика’” src=”img/first.png”>

    $(‘.poster’).each(function() {

    var elemDescription = $(this).data(‘desc’);

    if(elemDescription) {

    $(this).attr("title", elemDescription);
    

    }

    });

    В данном примере у всех элементов с классом poster берется data атрибут desc и если он был определен и он не пустой, то его содержимое добавляется в title этой же картинки. Такой вот простой пример. Можно использовать в контексте нажатия кнопки "Показать описание".

    События на странице. Создание интерактивных страниц

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

    Что такое события ?

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

    **Список событий мыши **

    • click Срабатывает когда мы нажимаем и отпускаем левую кнопку мыши (клик)

    • dblclick Срабатывает когда мы делаем двойной клик левой кнопкой мыши

    • mousedown Срабатывает когда мы нажали на левую кнопку мыши

    • mouseup Срабатывает когда мы отпустили левую кнопку мыши

    • mouseover Срабатывает когда курсор находится или проходит над элементом

    • mouseout Срабатывает когда мы уводим курсор с элемента

    • mousemove Срабатывает всегда, когда курсор перемещается.

    Список событий окна

    • load Запускается, когда браузер закончил загрузку всех файлов: веб-страницы: HTML, CSS, JS, картинки и прочее

    • resize Запускается, когда пользователь меняет размер окна браузера

    • scroll Запускается, когда вы пользователе прокручивает страницы. Если прокручивать некуда - событие не работает.

    • unload Запускается, когда вы щелкаете по ссылке для перехода на другую страницу, закрываете вкладку в окне браузера или само окно.

    Список событий формы

    • submit Запускается, когда пользователь отправляет данные формы с помощью щелчка по кнопке Отправить (<input type="submit” value=”Отправить”>)

    • reset Запускается, когда пользователь отменяет изменения кнопкой Отменить (<input type="reset” value=”Отменить”)

    • change Запускается, когда мы меняем переключатель, например чекбокс

    • focus Запускается, когда поле ввода становится активным при переходе в него

    • blur Запускается, когда поле ввода неактивно, не изменяется

    События клавиатуры

    • keypress Запускается, когда одна или несколько клавиш на клавиатуре нажаты

    • keydown Запускается, в момент нажатия на клавишу

    • keyup Запускается, когда мы отпускаем клавишу

    Использование событий

    Алгоритм обработки событий очень простой:

    1. Выберите элемент(ты) :

    $(‘.btn’)

    1. Добавьте событие :

      $(‘.btn’).click();

      $(‘.btn’).mouseover();

      $(window).resize();

      $(‘.phone’).focus();

    2. Добавьте функцию-обработчик события:

    $(‘.btn’).click(function() { //ваш код здесь });

    Это все. Есть специфичные функции, такие как .hover() , которые принимают две функции-обработчика - при наведении курсора, при его выходе.

    $(‘.poser’).hover(function(){

    //Описываем действия при наведении

    }, function() {

    //Описываем действия обратного действия

    });

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

    $(‘.poster’).hover(showElement, hideElement); //без круглых скобок. Передаем как значение

    Объект события

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

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

    $(‘.btn’).click(function(event) {

    var xCoord = e****vent.pageX;

    var yCoord = e****vent.pageY;

    alert("X : " + xCoord + “, Y: “ + yCoord );

    });

    Переменная **event **и будет хранить объект события. В строке 2 и 3, мы работаем с ним и получаем данные координат курсора мыши, на момент события.

    **Свойства объекта событий

    **

    • pageX Расстояние в пикселях от указателя мыши , до левого края окна браузера

    • pageY Расстояние в пикселях от указателя мыши, до верхнего края окна браузера

    • screenX Расстояние в пикселях от мыши до левого края монитора

    • screenY Расстояние в пикселях от мыши до верхнего края монитора

    • shiftKey true - если клавиша Shift были нажата, когда происходило событие

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

    • target Объект, бывший целью события

    Отмена обычного поведения событий

    Некоторые элементы HTML - кода имеют заранее запрограммированные реакции на события. Например, при щелчке по ссылке обычно загружается новая веб-страница; щелчок по кнопке подтверждения формы отсылает данные на веб-сервер для обработки. Иногда вы хотите, чтобы браузер повел себя не так, как обычно. Допустим, при подтверждении формы (событие submit()) вы можете пожелать остановить ее отправку, пока посетитель не внесет в форму недостающих важных данных.

    Функция preventDefault() позволяет отменить нормальное поведение браузера. Она является частью объекта события, поэтому доступ к ней осуществляется в рамках функции, управляющей событием. Пример:

    <a href="#” class=”btn”>Купить

    $(‘.btn’).click(function(event) { event.preventDefault(); // перехода по кнопке-ссылке не будет

    });

    Другой вариант - это просто возвращать "ложь" как результат выполнения функции. Например:

    <a href=”#” class=”btn”>Купить

    $(‘.btn’).click(function() { return false; // перехода по кнопке-ссылке не будет

    });

    Удаление событий

    Иногда может понадобиться удалить событие, которое мы присвоили элементу. Для этого существует функция off(). Например мы хотим удалить событие click на всех кнопках страницы :

    $(‘.btn’).off(‘click’);

    Более правдивый случай:

    $(‘a’).mouseover(function () {

    alert(‘Вы навели указатель мыши’);	
    

    });

    $(‘.disable-btn’).click(function () {

    $(‘a’).off(‘mouseover’);
    

    });

    Первые три строки кода, добавляют событие при наведении курсора мыши на элементы все , при котором пользователь уведомляется о том что он навел курсор мыши. Однако постоянное уведомление о таких событиях может раздражать пользователя, то для этого есть кнопка disable-btn, при клике на которую, событие mouseover у элементов удаляется с помощью функции off().

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

    $(‘.enable’).off();

    Профессиональное управление событиями

    Метод on() - это более гибкий способ работы с событиями по сравнению со специфичными jQuery-функциями, такими как click() или mouseover().

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

    Формат функции следующий :

    $(‘#modal’).on(‘событие’, ‘p.thank-text’, {}, del);

    Первый аргумент - имя события, например мыши.

    Второй аргумент не является обязательным, но если вы решите предоставить его значение , то используйте допустимый селектор tr, .callout, #alarm. Суть его использования - применить это событие к другому элементу в рамках выделенного элемента

    Эта техника называется делегированием событий и мы познакомимся с ней далее.

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

    {

    firstName: "Александр",
    
    secondName: "Коньков"
    

    }

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

    var flameMessage = {message: "Делайте домашки!"};

    Четвертый аргумент - наш коллбэк (функция обратного вызова, функция - обработчик).

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

    $(‘.btn’).on(‘click’, function () {

    //магия
    

    });

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

    var linkVar = {

    message: ‘Привет от ссылки’

    };

    var pVar = {

    message: ‘Привет от абзаца’

    };

    function showMessage(evt) {

    alert(evt.data.message); 
    

    }

    $(a).on(‘mouseover’, linkVar, showMessage);

    $(p).on(‘click’, pVar, showMessage);

    Или сокращенный вариант этих функций :

    $(a).on(‘mouseover’, {message: "Привет от ссылки"}, function(evt) {

    alert(evt.data.message);
    

    });

    $(p).on(‘click’, {message: "Привет от абзаца"}, function(evt) {

    alert(evt.data.message);
    

    });

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

    $(document).on(‘click keypress’, function() {

    $("#lightbox").hide();
    

    });

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

    Еще одна "фишка" функции .on() - если мы хотим обработать несколько событий для одного элемента, нам не нужно описывать их двумя вызовами функции on () :

    $(‘.btn’).on(‘mouseover’, function (){

    //очередная магия

    });

    $(‘.btn’).on(‘click’, function() {

    //и еще чуть чуть

    });

    Эту же обработку можно выполнить следующим образом :

    $(‘.btn’).on({

    ‘click’ : function () {

    },

    ‘mouseover’ : function() {

    },

    ‘dblclick’ : function () {

    }

    });

    **Делегирование событий с помощью функции on() **

    Как отмечалось ранее, метод on() может принимать второй аргумент, который является еще одним селектором :

    $(‘#selector’).on(‘event’, ‘selector’, callback);

    Второй аргумент может быть любым действительным селектором jQuery. Передача селектора функции on() может значительно повлиять на ее работу. Без передачи селектора, событие применяется к первоначальному селектору - $(‘#selector’). Допустим вы добавили на страницу такой код :

    $(‘li’).on(‘click’, function () {

    $(this).css(‘text-decoration’, ‘line-through’);
    

    });

    Этот код делает перечеркнутым текст в каждом элементе li, по которому щелкает посетитель. Внимание! Фрагмент $(this) относится к элементу, обрабатывающему событие, то есть к элементу li, по которому производится щелчок. Другими словами, событие click "связано" с элементом li.

    Тем не менее у такого подхода существует одна проблема : он работает только в тому случае, если элемент уже присутствует на странице. Если вы динамически добавляете HTML-код после добавления такого обработчика событий, как click, mouseout или on, то к этим новым элементам не будут определены никакие обработчики событий.

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

    $(‘p’).on(‘click’, ‘a’, function() {

    $(this).css(‘text-decoration’, ‘line-through’);

    });

    Анимация и эффекты jQuery

    image alt text

    Большинство программ jQuery подразумевает три действия: выбор элемента, прикрепление к нему события и реагирование на это событие путем выполнения каких-то действий. В этой части мы рассмотрим как можно реагировать на события , путем встроенных в библиотеку jQuery функций эффектов и анимаций. Кроме этого, мы узнаем как комбинировать анимацию CSS3 с инструментами jQuery, предназначенным для легкого создания анимационных эффектов.

    Эффекты jQuery

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

    Чтобы использовать каждый из доступных эффектов, вы должны применить их к выборке jQuery, как и любую другую функцию. Пример:

    $(‘.submenu’).hide(); //Скрыть все элементы с классом submenu

    Каждая из функций эффекта может иметь настройки скорости и функцию обратного вызова. Скорость эффекта можно указать в трех строковых значениях : ‘fast’, ‘normal’, ‘slow’; либо число, представляющее количество миллисекунд :

    $(‘.submenu’).fadeOut(‘slow’);

    $(‘.submenu’).fadeOut(1000);

    Элемент при сокрытии не удаляется из DOM.

    Простое отображение и сокрытие элемента

    • show() показывает ранее скрытый элемент. Принимает значение скорости анимации.

    • hide() скрывает видимый элемент. Принимает значение скорости анимации.

    • toggle() переключает текущее состояние элемента. Принимает значение скорости анимации.

    Постепенное появление и исчезновение элемента

    • fadeIn() заставляет отобразить элемент переходом из прозрачного состояния в обычное. Принимает значение скорости анимации.

    • fadeOut() заставляет скрыть элемент переходом из обычное состояния в прозрачное. Принимает значение скорости анимации.

    • fadeToggle() переключение.

    • fadeTo() работает иначе: она изменяет степень прозрачности элемента в диапазоне от 0 до 1 (или ‘normal’). Пример : $(‘.phone-number’).fadeTo(‘normal’, .75);

    Скользящие элементы

    • slideDown() появление элемента.

    • slideUp() скрытие элемента.

    • slideToggle() переключение.

    Анимация

    Библиотека jQuery не ограничивается только эффектами, встроенными в библиотеку. Используя функцию animate(), мы можем анимировать любое CSS свойство, принимающее числовое значение (пиксели, em или проценты). Например размер текста, позицию элемента на странице степень непрозрачности объекта или толщину границы.

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

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

    Пример :

    {

    left: ‘650px’,
    
    opacity: 0.5,
    
    fontSize: ‘24px’
    

    }

    Заметьте, что вы должны указывать значение в кавычках, только если оно включает единицу измерения, например px, em, %. В тоже время значение свойства opacity указывается без кавычек, т.к передается число, без указания единиц измерения. Обратите внимание и на свойство fontSize, которое имеет непривычный вид. Все потому что для JavaScript дефис имеет немного другое значение , а именно интерпретируется как минус. Поэтому для указания каких либо свойств имеющих дефис в названии используйте camelCase стиль написания, либо указывайте свойство в кавычках : ‘font-size’.

    Применение анимации к элементу :

    $(‘#message’).animate({

    left : ‘650px’,
    
    opacity: .5,
    
    fontSize: 24px 
    

    }, 1500);

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

    Также мы можем задать свойство относительно его текущего значения, используя операции += или -= как часть настроек анимации. Например, вы хотите анимировать элемент, сдвигая его на 50 пикселей вправо при каждом щелчке по нему кнопкой мыши:

    $(‘#toRight’).click(function() {

    $(this).animate({
    
    	left : ‘+=50px’
    

    }, 1000)

    });

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

    Управление скоростью анимации

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

    Библиотека включает два метода easing : swing и linear. Метод linear делает анимацию равномерной. Метод swing более динамический : анимация начинается в более быстром темпе,а затем замедляется. Метод swing установлен по умолчанию. Пример :

    $(‘#elem’).slideUp(1000, ‘linear’);

    $(‘#message’).animate({

    left: ‘650px’
    

    }, 1500, ‘linear’);

    Расширяет функционал плагин jQueryUI, которая содержит множество методов для управления скоростью анимации.

    Выполнение действия после завершения эффекта

    Иногда нам нужно сделать что-либо по завершении эффекта. Допустим, когда появляется фотография, мы хотим чтобы на экране появилась надпись. Другими словами, надпись должна появиться сразу после окончания анимации. Если в нашем коде есть строки, которые показывают картинку и строки которые показывают текст, то выполнятся они одновременно. Это не то что там нужно, поэтому для решения этой делемы, мы воспользуемся коллбэком. Функция передается в качестве второго аргумента:

    $(‘#title’).fadeIn(1000, function() {

    ** $(‘#message’).fadeIn(500)**

    });

    Для анимации, эта же функция передается после всех остальных аргументов :

    $(‘#title’).animation({

    ‘opacity’ : 1,
    
    ‘top’ : ‘200px’	
    

    }, 1000, ‘linear’, function(){

    ** $(‘#message’).fadeIn(500);**

    });

    Выгрузка сайта в интернет. FTP-передача данных.

    image alt text

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

    Разберем основные понятия и устройство работы веба.

    Что такое сервер?

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

    image alt text

    Для чего нужен сервер?

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

    • Одной из основных задач серверов является организация работы Интернет-провайдера. Сервер производит подключение пользователя и передаёт ему Интернет-трафик, являясь, таким образом, своеобразной базой. Кроме того, существует DNS-сервер который отвечает за преобразование символьных URL в IP-адреса. Любая услуга провайдера работает с сервера, в том числе и упомянутый в прошлых статьях proxy-сервер.

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

    • Ну и третий распространенный вид предназначения серверов – это хостинг. Хостинг – это сервер, на котором хранятся сайты и все файлы которые размещены на данном сайте.

    Подключение к серверу

    Когда мы вбиваем в адресную строку браузера название нашего сайта, мы, на самом деле, вбиваем IP адрес. Дело в том что, под каждым адресом сайта (google.com, vk.com, tut.by) в действительности скрывается IP адрес, вида 192.168.0.1 или любой иной. Все зависит от того к какому интернет-провайдеру подключен сам сервер. Преобразованием из адреса вида 192.168.0.1 в тот же tut.by, занимается DNS сервер, о котором мы читали выше. Само подключение отлично подходит под эту аналогию : Вбивая адрес, мы как будто идем по адресу, где находится физический дом в определенном городе.

    HTTP подключение

    Возвращаясь к аналогии с домами, можно с уверенностью сказать, что в большинстве случаев дома многоквартирные. Поэтому если мы идем по определенному адресу, нам нужно еще знать квартиру. В роли квартиры в серверах выступают порты. Полное подключение к сайту, выглядит вот так http://192.168.0.1:8080 . Порт 8080 - стандартный HTTP порт. HTTP (HyperText Transfer Protocol) - протокол передачи гипертекста. Это именно тот протокол, который нужен, чтобы отправлять страничку сайта пользователю. В итоге получается, что в большинстве случаев, мы подключаемся именно к 8080 порту, хотя диапазон HTTP портов намного шире. Поэтому по одному и тому же адресу может находиться несколько сайтов, за счет того что они находятся на разных портах. По адресу http://192.168.0.1:8080 - один сайт, по адресу http://192.168.0.1:8081 - другой.

    FTP подключение

    FTP(File Transfer Protocol) - протокол передачи файлов. Это именно то подключение, которое мы будем использовать , когда будем загружать файлы нашего сайта на сервер. Тут главное не бояться, явно указывать мы его нигде не будем. Все что нам тут нужно знать, это то что порт , по которому осуществляется передача данных - 21. Далее мы просто скачаем FTP-клиент - программу, передающую файлы на сервер и просто укажем этот порт. Правда прежде чем это сделать, нам нужно выбрать хостинг, чтобы арендовать себе место на сервере, для нашего сайта.

    Хостинг

    Как отмечалось выше, хостинг - это сервер, на котором хранятся сайты и все файлы которые размещены на данном сайте.

    Хостинги бывают разные, отличающиеся функционалом и ценой. Для наших целей подойдет и самый простой. Возьмем бесплатный российский хостинг hostinger.ru.

    FTP-client

    FTP-client - программа, которая передает файлы на сервере по FTP подключению. Самая популярная и распространенная - FileZilla. Скачать ее можно с официального сайта - filezilla.

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

    image alt text

    Bower - пакетный менеджер, который упрощает установку и обновление зависимостей проекта, то есть сторонних библиотек: jQuery, Fotorama, Bootstrap, Slick, Font awesome и т.д - всё, что используется на вашем сайте и написано не вами.

    Помимо Bower существуют и другие пакетные менеджеры. Например npm, Bundler, Cargo и недавно появившийся yarn от Facebook.

    Но как и для bower, так и для yarn, родителем является npm. Npm поставляется вместе с node.js.

    npm (аббр. node package manager) — это стандартный менеджер пакетов, автоматически устанавливающийся вместе с Node.js. Он используется для скачивания пакетов из облачного сервера npm, либо для загрузки пакетов на эти сервера.

    (Вкратце, пакетом в Node.js называется один или несколько JavaScript-файлов, представляющих собой какую-то библиотеку или инструмент).

    На данный момент Bower — это, наверное, самый популярный менеджер для клиентского javascript. Все, чем занимается Bower — устанавливает пакеты вместе с их зависимостями.

    Итак, для установки Bower в систему, достаточно открыть терминал (Linux / Mac) или командную строку (Windows) от Администратора и выполнить команду :

    npm install bower -g

    Здесь флаг -g указывает на глобальную установку Bower’а, т.е он будет доступен в любой папке нашей системы. Это очень удобно и освобождает нас от установки его каждый раз в папке нашего проекта, но установку можно выполнить локально - в пределах директории нашего проекта. Для этого флаг -g следует опустить.

    Далее переходим в директорию нашего проекта и выполняем следующую команду :

    bower init

    В ходе выполнения данной команды, инициализация бовера, подобно инициализации npm, спросит у нас несколько вопросов о названии нашего проекта, адресе git - репозитория, стартовом файле и т.д . Это можно пропустить , нажимая клавишу Enter. Для тестового проекта мы так и поступим.

    После инициализации бовера, в той же командной строке или терминале, мы можем обращаться к боверу за получением пакетов (установкой библиотек). Например :

    bower install jquery --save

    Флаг --save указывает на то что пакет должен сохраниться с именем пакета, его версией в файл-манифест - bower.json, который появился после нашей инициализации.

    Вообще рекомендуется указывать флаг -- save для всех библиотек, которые мы получаем через bower. Это делается для вашего и ваших коллег по проекту удобства.

    Допустим вы отдаете работу над проектом другому разработчику. Вместо того чтобы передавать проект с кучей файлов библиотек, можно передать файлы проекта (css, img, js, index.html) и файл-манифест bower.json. Получивший такую сборку разработчик, может просто выполнить команду bower install и все пакеты , помеченные ранее вами флагом --save , успешно установятся для другого разработчика. Это очень удобно.

    Перед скачиванием библиотеки через бовер, также рекомендуется посещать страницу проекта на github. Дело в том что некоторые библиотеки требуют установки еще с одним флагом : -dev. Этот флаг указывает на сохранение зависимостей. Не ленитесь, сделайте поиск вашей библиотеки на github. В большинстве случаев, на главной странице проекта, есть описание о том как установить ее через bower.

    "По дефолту" bower сохраняет пакеты в свою папку bower_components. Это не совсем удобно и отредактировать это можно, создав файл .bowerrc (точка перед именем обязательна). В данном файле мы напишем следующее :

    {

    ‘directory’ : ‘libs/’
    

    }

    Здесь указывается путь установки пакетов. В данном примере это папка в корне проекта, которая называется libs.

    Bower позволяет просмотреть список всех установленных пакетов :

    bower list

    Чтобы удалить пакет используйте команду uninstall:

    bower uninstall

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

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

    image alt text

    Gulp — это инструмент сборки веб-приложения, позволяющий автоматизировать повторяющиеся задачи, такие как сборка и минификация CSS- и JS-файлов, запуск тестов, перезагрузка браузера и т.д. Тем самым Gulp ускоряет и оптимизирует процесс веб-разработки.

    Gulp построен на Node.js, и файл сборки пишется на JavaScript. Сам по себе Gulp умеет не очень много, но имеет огромное количество плагинов, которые можно найти на странице со списком плагинов или просто поиском на npm. Например, есть плагины для запуска JSHint, компиляции Less, запуска тестов и даже для обновления номера версии сборки.

    Помимо Gulp, существуют и другие таск-менеджеры. Один из них **Grunt **. Grunt - отец таск-менеджеров , но имеет существенные недостатки. Работа Grunt’а в сравнении с Gulp’ом - в 6 раз медленнее! Но плагинов Grunt имеет почти в 3 раза больше. (11 тысяч у Grunt и 4.5 тысячи у Gulp). Но для фронтенд разработки все плагины существуют и для Gulp, поэтому для работы выбираем именно его.

    Для того чтобы начать работу с Gulp, нам нужен установленный Node.js. Об установки Node.js я рассказывать не буду и буду думать что он у вас уже установлен.

    Теперь установим Gulp глобально , выполнив команду в терминале или командной строке, открытой от имени администратора :

    npm install gulp -g

    Далее переходим в папку нашего проекта и делаем инициализацию проекта.

    npm init

    И соглашаемся со всем что у нас спрашивают, либо заполняем поля. После завершения инициализации, в нашем проекте появится файл package.json.

    Файл package.json является файлом манифеста нашего проекта, который описывает помимо той информации, что мы внесли в терминале, еще и информацию об используемых пакетах в нашем проекте.

    Например, если мы установим в проект Gulp с флагом --save-dev, то пакет и используемая версия автоматически добавится в наш package.json. Такой учет позволит быстро разворачивать новый проект с использованием уже имеющегося package.json и устанавливать необходимые модули с зависимостями, которые прописаны в package.json в новых проектах.

    Далее устанавливаем Gulp в папку нашего проекта с сохранением зависимостей :

    npm install gulp --save-dev

    Завершим подготовку, созданием пустого файла gulpfile.js.

    Gulp таски

    Откроем файл gulpfile.js и добавим следующую строчку :

    var gulp = require('gulp');

    Данной строчкой мы подключаем Gulp к нашему проекту, посредством функции require. Данная функция подключает пакеты из папки node_modules в наш проект, присваивая их переменной. В данном случае, мы создаем переменную gulp.

    Далее мы уже можем работать с этой переменной и создавать таски (инструкции).

    Типичный таск для Gulp выглядит следующим образом :

    gulp.task('mytask', function () {

    return gulp.src('source-files') // Выборка исходных файлов

    .pipe(plugin()) // Вызов Gulp плагина для обработки файла
    
    .pipe(gulp.dest('folder')) // Вывод результирующего файла в папку назначения (dest - пункт назначения)
    

    });

    • gulp.src - выборка исходных файлов проекта для обработки плагином;

    • .pipe(plugin()) - вызов Gulp плагина для обработки файла;

    • .pipe(gulp.dest('folder')) - вывод результирующего файла в папку назначения (dest - пункт назначения).

    Это база Gulp, теперь можно создавать инструкции. Для начала давайте создадим обработчик, который будет компилировать Less файлы в CSS (CSS препроцессинг).

    Добавление Gulp плагинов

    Любые Gulp пакеты, легко гуглятся и имеют вполне исчерпывающие инструкции по подключению на своих хоумпейджах и в документации. Подключим основные , которые понадобятся нам в работе.

    Gulp less

    Установим плагин для компиляции Less файлов в CSS с сохранением версии и названия в package.json :

    npm i gulp-less --save-dev

    Далее подключим gulp-less в файле gulpfile.js. Обратите внимание, что переменные для подключения пакетов можно перечислять через запятую :

    var gulp = require('gulp'),

    less = require('gulp-less'); //Подключаем Less пакет
    

    Теперь напишем таск для Gulp по компиляции Less в Css :

    var gulp = require('gulp'), // Подключаем Gulp

    less = require('gulp-less'); //Подключаем Less пакет
    

    gulp.task('less', function(){ // Создаем таск "less"

    return gulp.src('less/main.less') // Берем источник
    
        .pipe(less()) // Преобразуем Less в CSS посредством gulp-less
    
        .pipe(gulp.dest('css/')) // Выгружаем результата в папку css
    

    });

    Выполним таск в терминале :

    gulp less

    Таск выполняется, преобразуя наш Less файл в CSS и помещает файл main.css в соответствующую папку.

    Самые распространенные шаблоны выборки

    *.less- выбирает все файлы, имеющие определенное расширение (в данном случае, .less) в корневой папке проекта.

    **/*.js - выбирает все файлы с расширением .js во всех папках проекта.

    !header.less - исключает файл из общей выборки

    *.+(less|sass) - задает комплексный шаблон для нескольких типов файлов, разделенных вертикальной чертой. В данном примере в выборку попадут любые sass и less файлы в корне проекта.

    Теперь внесем некоторые правки в наш less таск для галпа.

    gulp.task('less', function(){

    return gulp.src(‘less/**/*.less') // Берем все less файлы из        папки less и дочерних, если таковые будут
    
        .pipe(less())
    
        .pipe(gulp.dest('css/'))
    

    });

    Дело в том, что брать напрямую один отдельный файл не всегда удобно, так как в папке less могут появиться и другие файлы с расширением less, которые могут использоваться в проекте.

    Обратите внимание, что файлы less, которые предназначены для импорта в другие файлы, как части одного общего, начинаются с нижнего подчеркивания _header.less. Такие файлы не участвуют в компиляции, как отдельные файлы, а добавляются через @import в основные файлы.

    Наблюдение за изменениями в файлах (Gulp Watch)

    Gulp поддерживает метод watch для проверки сохраняемых файлов и имеет следующий синтаксис:

    gulp.watch('watch-files', ['task1', 'task2']);

    Если мы, например, хотим наблюдать за всеми изменениями в файлах less нашего проекта, то можем использовать следующую конструкцию:

    gulp.watch(‘less/**/*.less', ['less']);

    Что мы видим: Gulp наблюдает за всеми less файлами и при сохранении выполняет таск less, который автоматически компилирует их в css файлы.

    Также, мы можем создать отдельный таск для наблюдения за всеми необходимыми файлами

    gulp.task('watch', function() {

    gulp.watch('less/**/*.less', ['less']); // Наблюдение за less файлами
    
    // Наблюдение за другими типами файлов
    

    });

    Если мы запустим в консоли gulp watch, то Gulp будет автоматически следить за всеми изменениями в файлах less при сохранении и компилировать их в css.

    Было бы неплохо в дополнение к этой красоте сделать автоматическую перезагрузку страницы при изменениях в файлах. Для этой задачи нам подойдет Browser Sync.

    **Автоматическое обновление страниц с использованием Browser Sync **

    Browser Sync - это отличное решение для LiveReload страниц при сохранении файлов. При чем релоад происходит не только в одном браузере, но и во всех браузерах сети, будь это мобильные устройства или другие компьютеры в одной Wi-Fi сети и локальной сети.

    Мы уже умеем устанавливать дополнения для Gulp, поэтому давайте установим Browser Sync в наш проект:

    npm i browser-sync --save-dev

    И, конечно-же, подключим в файле gulpfile.js, как мы это делали ранее с пакетом gulp-less :

    var gulp = require('gulp'), // Подключаем Gulp

    less        = require('gulp-less'), //Подключаем Less пакет,
    
    browserSync = require('browser-sync'); // Подключаем Browser Sync
    

    Создаем таск для Browser Sync:

    gulp.task('browser-sync', function() { // Создаем таск browser-sync

    browserSync({ // Выполняем browser Sync
    
        server: { // Определяем параметры сервера
    
            baseDir: './' // Директория для сервера - корень
    
        },
    
        notify: false // Отключаем уведомления
    
    });
    

    });

    Отлично! Наш сервер для работы и автоматического релоада готов. Теперь давайте проследим за изменениями в Less. Если файл Less обновляется, автоматически инжектим в HTML измененный CSS файл:

    gulp.task('less', function(){ // Создаем таск Less

    return gulp.src('less/**/*.less') // Берем источник
    
        .pipe(less()) // Преобразуем Less в CSS посредством gulp-less
    
        .pipe(gulp.dest('css/')) // Выгружаем результата в папку css/
    
        .pipe(browserSync.reload({stream: true})) // Обновляем CSS на странице при изменении
    

    });

    Все, что нам осталось сделать - это запустить таск browser-sync перед тем, как запустится gulp watch. Немного модифицируем таск watch, добавив выполнение browser-sync и less до запуска watch :

    gulp.task('watch', ['browser-sync', 'less'], function() {

    gulp.watch('less/**/*.less', ['less']); // Наблюдение за less файлами
    
    // Наблюдение за другими типами файлов
    

    });

    Обратите внимание, что мы выполняем таски ['browser-sync', 'less'] до запуска watch, так как их выполнение необходимо нам для корректного отображения изменений на момент запуска сервера.

    Расположим таск watch после всех других тасков и в результате получим такой gulpfile.js:

    var gulp = require('gulp'), // Подключаем Gulp

      less        = require('gulp-less'), //Подключаем Less пакет,
    
      browserSync = require('browser-sync'); // Подключаем Browser Sync
    

    gulp.task('less', function(){ // Создаем таск Less

    return gulp.src('less/**/*.less') // Берем источник
    
        .pipe(less()) // Преобразуем Less в CSS посредством gulp-less
    
        .pipe(gulp.dest('css/')) // Выгружаем результата в папку css
    
        .pipe(browserSync.reload({stream: true})) // Обновляем CSS на странице при изменении
    

    });

    gulp.task('browser-sync', function() { // Создаем таск browser-sync

    browserSync({ // Выполняем browserSync
    
        server: { // Определяем параметры сервера
    
            baseDir: 'app' // Директория для сервера - app
    
        },
    
        notify: false // Отключаем уведомления
    
    });
    

    });

    gulp.task('watch', ['browser-sync', 'less'], function() {

    gulp.watch('less/**/*.less', ['less']); // Наблюдение за less файлами
    
    // Наблюдение за другими типами файлов
    

    });

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

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

    Практическая часть: JS и jQuery

    image alt text

    В этой части мы проверим полученные знания по JavaScript и библиотеке jQuery. Создайте каталог dom-kino и добавьте в него обязательный index.html, main.css, main.js и библиотеку jQuery. Заведите каталоги для стилей, скриптов и прочего (Я не создавал директории app и dist, мой gulpfile настроен на работу с корневой директорией). Структура может отличаться. Например за основу может быть взята одна из самостоятельных работ (но не домашние, которые верстались с макета).

    Разрешено пользоваться Gulp и Bower.

    *Если используете мой gulpfile.js и *_package.json: _

    1. Поместите package.json в ваш каталог

    2. В терминале установите пакеты (gulp, bower, less) командой npm install

    3. Заведите директорию libs для библиотек и создайте .bowerrc

    4. Инициализируйте директорию библиотек {"directory" : “libs/”}

    5. Все готово! Устанавливайте библиотеки через bower, запускайте таск gulp.

    ** **Сам галп наблюдает за главным файлом стилей, index.html и main.js.

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

    Удовлетворительное время на выполнение задания - 2.5 часа.

    Максимум за задание можно набрать 10 баллов. Данная оценка не характеризует ваши знания в целом и уместна только в пределах этого теста.

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


    1. Создать произвольный объект в JS и функцию, выводящую его свойства**(1 балл)**

    Используйте цикл for...in в функции, для перебора свойств. Для отображения результата используйте console.log().

    1. **Добавить слайдер на страницу(2 балла) **

    Используйте любой слайдер, на котором можно реализовать данный функционал. Это может быть slick или swiper, либо любой другой. В слайдере должно быть 9 фотографий и кнопки переключения. Определить слайдер, при этом, нужно с такими настройками :

    	- По 3 слайда к показу 
    	- Автоматическое переключение на следующий слайд
    
    	- Повторяющийся по кругу ( бесконечный )
    
    	- Со скоростью переключения 2 секунды
    
    	- С fade effect 
    
    1. **Показать скрытый элемент на странице путем переключения состояния, по кнопке(2 балла) **Верстка такого элемента и кнопки. Обработка события на jQuery.

    2. Обработать событие scroll, через функцию on и применить ее , например, к хэдеру(2 балла)

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

    1. Реализовать простейший калькулятор на странице(3 балла)* Верстка поля для ввода (input=’text’) и окно выбора количества (select). Математические вычисления происходят по клику на кнопку "Рассчитать" . Например это может быть расчет стоимости билетов в кино.

    jspace's People

    Watchers

    James Cloos avatar

    Recommend Projects

    • React photo React

      A declarative, efficient, and flexible JavaScript library for building user interfaces.

    • Vue.js photo Vue.js

      🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

    • Typescript photo Typescript

      TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

    • TensorFlow photo TensorFlow

      An Open Source Machine Learning Framework for Everyone

    • Django photo Django

      The Web framework for perfectionists with deadlines.

    • D3 photo D3

      Bring data to life with SVG, Canvas and HTML. 📊📈🎉

    Recommend Topics

    • javascript

      JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

    • web

      Some thing interesting about web. New door for the world.

    • server

      A server is a program made to process requests and deliver data to clients.

    • Machine learning

      Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

    • Game

      Some thing interesting about game, make everyone happy.

    Recommend Org

    • Facebook photo Facebook

      We are working to build community through open source technology. NB: members must have two-factor auth.

    • Microsoft photo Microsoft

      Open source projects and samples from Microsoft.

    • Google photo Google

      Google ❤️ Open Source for everyone.

    • D3 photo D3

      Data-Driven Documents codes.