Javascript что это такое простыми словами для чайников
Перейти к содержимому

Javascript что это такое простыми словами для чайников

  • автор:

Javascript — что это такое? Простыми словами!

Javascript — что это такое? Простыми словами!

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

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

Мы коснемся только web-части языка JavaScript, а именно его синтаксис и библиотеку JQuery.

Для чего используется JavaScript?

В основном, с помощью JS, а именно JQ, разрабатываются дополнительные элементы для сайта. Вы могли неоднократно видеть набор слайдеров на сайте, интерактивные карты, даже калькуляторы для продающих сайтов, всё это делается при помощи JavaScript.

Кроме этого, JavaScript отлично подходит для создания 2D и 3D анимации. Его можно использовать для создания динамического контента, анимированного контента.

Что может делать ядро языка?

Выше мы перечислили возможные элементы веб-дизайна, которые можно создать, а сейчас мы расскажем о возможностях самого языка:

  1. JavaScript позволяет хранить данные внутри переменных и объектов. Для этого достаточно создать переменное и записать туда какие-либо данные.
  2. Работа со строками. JavaScript позволяет работать с текстовым контентом, изменять его или добавлять новый.
  3. Использование интерактивных событий. JavaScript дает возможность создавать элементы, которые будут появляться при определенных действиях пользователя.

Кроме этого, JavaScript имеет множество различных API.

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

Существует огромное множество API, некоторые из которых мы рассмотрим в следующих статьях.

Пример JavaScript кода:

Пример кода

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

Заключение

Как мы поняли, JavaScript — следующая ступень в веб-программировании, после HTML и CSS. Он довольно сложный, но в последующих статьях мы поможем вам разобраться во всех его тонкостей.

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

Особенности JavaScript: зачем учить этот язык программирования и где он пригодится

Javascript – это мультипарадигменный язык программирования. Он используется в веб-браузерах, на нем можно писать игры, разрабатывать различные приложения для компьютера и мобильных устройств, создавать серверную часть сайта и производить прочие интересные вещи. Воу-воу, не слишком ли много Javascript берет на себя? Давайте обо всем по порядку.

История возникновения JavaScript

Давным-давно, когда на планете Земля жили еще динозавры, в 1995 году, компания-мастодонт Netscape поставила задачу своему разработчику Брендану Айку создать язык программирования для своего браузера, чтобы решить вопрос взаимодействия с пользователем. Выпуск языка состоялся как раз перед релизом второй бета-версии браузера Netscape Navigator 18 сентября 1995 года. Также нужно отдать должное компании Sun, без которой этого бы не случилось. Именно они были теми руками, которых так не хватало в Netscape: специалисты помогли ускорить процесс разработки в несколько раз и успеть как раз вовремя.

Первоначально язык программирования имел следующие названия: Mocha, Livescript, LiveWire (для серверной части). Поскольку в то время огромной популярностью пользовались языки C и Java, создатели решили «хайпануть» и дали название своему детищу – Javascript.

Параллельно их конкурент Microsoft трудился над своим браузером Internet Explorer, и в версии 3.0 у них вышел релиз собственного языка программирования под названием Jscript. Тут же встал вопрос: как дальше действовать и развиваться при наличии двух языков?

Спустя некоторое время инициативу в свои руки взял Netscape и провел стандартизацию языка через ассоциацию ECMA. Рабочая группа TC-39 присвоила стандарту имя ECMA-262. Возникали проблемы с торговой маркой ECMA, так как она не могла использовать Javascript в качестве названия.

После дебатов было решено, что описанный стандартном язык будет называться ECMAScript. Выходит так, что на сегодняшний день Javascript является по своей сути коммерческим названием ECMAScript. Кстати, на момент публикации статьи ожидается выход новой версии ECMAScript 2021.

Особенности языка программирования JavaScript

В мире frontend-разработки все строится на трех китах: HTML, CSS, Javascript. HTML отвечает за каркас страницы, CSS – за стилизацию страницы, Javascript – за создание интерактива на странице.

Что можно создать при помощи Javascript:

  • динамический контент
  • анимацию 2D/3D графики
  • веб-приложения
  • игры
  • управление мультимедией и много другое.

И это далеко не полный список. Самый типичный пример работы Javascript – это слайдер на странице. На нашем сайте мы как раз используем подобные.

пример слайдера на сайте

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

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

Преимущества и недостатки JavaScript

С каждым годом язык развивается и дополняется новыми крутыми вещами.

Преимущества JavaScript:

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

Востребованный язык программирования. Если верить статистике, Javascript входит в топ-3 языков программирования в мире.

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

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

Недостатки JavaScript:

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

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

Динамическая типизация. Причина частых проблем при разработке – нет возможности выявить ошибки заранее, только на этапе работы. Еще Javascript игнорирует явные несостыковки, которые прямо-таки бросаются в глаза. Поэтому это настоящая боль для человека, который захотел изучить Javascript после освоения строго типизированного языка (Java, C, C++).

Больше статей на схожую тематику:

Изучение языка программирования Javascript: стоит ли начинать?

Как уже было сказано, на сегодняшний день Javascript является одним из популярных и востребованных языков программирования. Есть желание научиться создавать крутые веб-сайты и веб-приложения? Хочется писать код для серверной части? Вас привлекает разработка мобильных и настольных приложений? Ответ один – изучайте Javascript!

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

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

Стоит сделать большую оговорку. Если вы желаете сменить профессию и полностью погрузиться в мир web-разработки, то лучше всего начать путь с основ построения страниц. Речь идет о HTML и CSS. HTML – скелет страницы сайта, он задает структуру. CSS – занимается стилизацией страницы: задается цвет, описывается сетка, по которой будут располагаться блоки на страницы, добавляется анимация, пишется адаптация под разные устройства и много другое. Данный процесс называется версткой сайта. Без знания верстки будет трудно, ведь HTML, CSS и JS сильно связаны между собой.

Как используется Javascript на сервере

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

Логотип node.js

Node.js – это платформа для работы с Javascript на сервере посредством движка V8.

Пару слов о движках. Движки необходимы для того, чтобы наш код поняла машина. Движок занимается трансляцией Javasctipt-кода в машинный код. Из популярных сегодня можно отметить V8 (Google Chrome) и SpiderMonkey (Mozilla Firefox). Стоит сказать, что SpiderMonkey – один из самых старых движков: когда-то он был разработан в компании Netscape Бренданом Айком, о котором мы говорили ранее. Таким образом, Node.js позволяет нам выполнять различные действия на стороне сервера.

Почему же произошел взлёт этой технологии? И в чем отличие классического взаимодействия сервера с пользователем от взаимодействия с использованием Node.js?

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

Вроде все нормально, все работает и крутится. Вы можете задать логичный вопрос: что же здесь не так? Проблемы начинаются, когда потоков становится много из-за большого количества пользователей. Ресурсы у железных монстров ограниченные и на всех пользователей может не хватить. Сервер в итоге будет переключаться между потоками, тогда может наступить потоковое голодание. Суть явления в следующем: каналов может стать настолько много, что процессор будет занят только переключением между ними и проверкой их состояния. Решается это расширением аппаратного комплекса, но не каждый готов на это пойти – слишком дорогое удовольствие.

Фишка Node.js в ее асинхронности. Объясняя упрощенно, могу можно сказать следующее: представим, что у нас запущено приложение на сервере, и к нему подключаются сразу три пользователя – всем им нужны какие-то сведения из базы данных.

Node.js сразу же хватает информацию из базы с помощью Libuv. Как раз Libuv асинхронен и может создавать свои параллельные, а не последовательные запросы в базу. Далее Libuv помещает информацию в главный поток, который крутит V8. Главный поток обрабатывают эту информацию в обработчиках, мутирует ее каким-то образом и точно такими же способами передает ее пользователю.

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

Нравится статья? Тогда смотрите наши курсы!

Библиотеки и фреймворки JavaScript

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

Библиотеки Javascript

Библиотека – это своего рода подпрограмма, набор элементов для более быстрой и удобной разработки сайта, приложения. Пожалуй, самой популярной Javasctipt-библиотекой является Jquery. Она появилась на свет в начале далекого 2006 года. По сей день у нее остается множество поклонников, ее используют тысячи людей. Успех заключается в том, что она предоставляет хорошие возможности для взаимодействия с элементами на странице, позволяет удобно обмениваться данными с сервером посредством Ajax и многое другое.

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

Фреймфорки Javasctipt

Все разработчики на проекте могут писать совершенно разный код, по-разному решать задачи. Фреймворки помогают писать быстрее, качественнее, а еще они в некоторой степени создают ограничения, тем самым программисты на проекте пишут почти одинаковый код. Это, несомненно, плюс, ведь гораздо лучше, когда есть некие рамки написания кода. Хочется отметить, что это не главное преимущество, а скорее последствия применения. У каждого фреймворка «свой язык», свои конструкции, но они все также имеют под собой базу под названием Javascript.

Более современным, модным, молодежным при разработке является использование одного из 3-х популярных фреймворков: Vue, Angular или React.

React

Логотип React

React был создан компанией Facebook в середине 2013 года. Изначально его разработали для решения внутренних задач компании. Стоит оговориться, что React позиционируется как библиотека, а не фреймворк. React по мере своего развития получил очень много возможностей. С его помощью можно создавать одностраничные SPA (Single Page Application) и мобильные приложения.

Ярким примером SPA является Gmail. Суть заключается в том, что приложение работает в рамках одной страницы, не происходит переход на другие, а различные его элементы подгружаются по мере надобности. У React развитая экосистема, он обладает множеством плагинов, дополнений, которые расширяют его возможности. Например: Redux, Mobx, Next, React Router, Recoil, Zustand, Xstate, React Native.

Angular

Логотип Angular

Angular – это детище Google inc. Появился на свет в 2009 году. Изначально разрабатывался Мишко Хевери и Адамом Абронсом в Brat Tech LLC как программное обеспечение, но спустя некоторое время Абронс покинул проект. Хевери, работающий в тот момент в Google, продолжил развивать Angular при поддержке своих коллег.

Философия фреймворка заключается в декларативном HTML-first подходе. Смысл HTML-first – в расширении HTML посредством внедрения некоторых конструкций. Таким образом разрабатываются более удобные, интуитивно понятные интерфейсы для пользователей, нежели при императивном подходе, который используется в React.

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

Vue

Логотип Vue

Vue был написан всего лишь одним разработчиком Эваном Ю. В какой-то момент Эван понял, что весьма затруднительно и почти невозможно быстро сделать прототип сложного интерфейса пользователя в веб-приложении.

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

Vue взял в себя лучшее, что было у других инструментов. К примеру, Vue и React используют технологию Vurtual DOM, которая опирается на корневую библиотеку. Angular и Vue очень похожи по синтаксису, так как оба используют HTML-first подход. Vue на данный момент любимец общества web-разработчиков, на него возлагаются большие надежды.

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

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

VS Code, Slack, WhatsApp Desktop, Discord, Skype, Twitch, Figma – все эти приложения написаны с использованием Javascript. GitHub – самый крупный веб-сервис для ведения IT проектов, его еще в шутку называют «социальная сеть для IT-разработчиков». Этот сервис разработал и выпустил на свет в 2013 году фреймворк под названием Electron.

Логотип Electron

Данный фреймворк использует в себе Node.js для работы с серверной частью и Chromium – для отображения визуальной части приложения.

Приложения, созданные с его помощью, можно запускать на любой платформе, будь то Linux, Windows или Mac. Если сказать очень утрированно, то программа, созданная на базе данного фреймворка, – это тот же самый веб-браузер, только оформленный слегка по-другому. Выходит, что если вы сможете сделать сайт, то вы напишете свое настольное приложение. Особенно это удобно, когда фреймворк сам заботится о сложных вещах, а пользователю можно сконцентрироваться на самых главных частях программы.

Кроссплатформенность react native

Javascript не обходит стороной и мобильную разработку приложений. В данном случае используется кроссплатформенный фреймворк React Native. Он поддерживает Android, Android TV, iOS, macOS и другие платформы. Самое важное заключается в том, что при использовании данного фреймворка автоматически становятся доступными возможности библиотеки React, которая используется в создании сайтов. Примерами написанных приложений могут стать Instagram, Facebook Ads, Uber eats, 2048, Bloomberg и многие другие.

Примеры роста кликов, конверсий, заказов и прибыли:

Итого

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

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

Введение в JavaScript ⁠ ⁠

Введение в JavaScript IT, Программирование, Web-программирование, Javascript, Самоучитель, Саморазвитие, Верстка, Длиннопост

Этот пост посвящён главному языку будущего — JavaScript. Благодаря своей гибкости используется в браузере, на серверах, в мобильных приложениях, на десктопе и практически во всех видах программирования. Удобный синтаксис позволяет легко писать на нём, а высокая производительность делает его отличным выбором для решения любых задач — от небольших магазинов до огромных highload проектов. JavaScript по праву является самым популярным в мире языком. На каждом сайте есть браузерный JavaScript, а JavaScript на сервере используется такими крупными корпорациями, как Amazon, Yahoo, HP, NASA, Walmart и многие другие.

Часто задаваемые вопросы

В: Что это за язык такой?

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

В: Какие возможные направления для разработки существуют?

О: Практически все! Можно писать Front-end, Back-end, GameDev, 2D/3D графику, разрабатывать мобильные и десктопные приложения. Список инструментов для различных целей

В: Можно выучить только один фреймворк/библиотеку и всё писать на нём?

О: Не стоит начинать учить отдельный фреймворк или библиотеку, пока отсутствуют базовые знания самого языка. Во-первых, из-за отсутствия знаний самого языка возникнет масса проблем с пониманием принципа работы фреймворка/библиотеки, во-вторых, этим можно сильно испортить себе восприятие языка и после этого будет гораздо сложнее изучать чистый JS и другие фреймворки.

В: Существуют ли стайл-гайды для JavaScript?

В: Какие новые возможности добавил ES6?

О: Вот здесь можно почитать на русском

В: Я хочу писать на ES6, но многие браузеры не поддерживают новые возможности. И вообще, надоел геморрой с браузерным зоопарком. Неужели нет способа обойти это?

О: Конечно есть! Чтобы код одинаково хорошо работал во всех браузерах и все возможности ES6 и будущих стандартов нормально работали необходимо собрать код с помощью сборщика. Сборщик компилирует весь код в один файл и делает его полностью кроссбраузерным. Наиболее удобен в использовании Webpack, хотя существуют и аналоги. Потребуется некоторое время на изучение, но результат себя окупит. Сборщики нужны только во Front-end, Node.js и так поддерживает все новые возможности.

В: Зачем нужны CoffeeScript и TypeScript?

О: Это особые варанты JS для любителей других языков. CoffeeScript подходит для любителей Ruby и Python, TypeScript — для сторонников строготипизированных языков вроде C# или Java. Если ты новичок в программировании, то учи оригинал, а диалекты попробуешь, когда уже будет опыт.

В: Зачем нужны таск-раннеры, такие как Gulp или Grunt?

О: Они позволяют одной консольной командой запустить выполнение заранее прописанного процесса, который может содержать множество команд и который неудобно каждый раз выполнять вручную. Пример — компиляция JS с помощью Webpack, сборка LESS стилей в CSS и многое другое. Ещё раз — таск-раннер не замена сборщику, Gulp — не конкурент Webpack, они выполняют совершенно разные задачи и зачастую используются вместе.

В: Можно ли писать фронт на других языках?

О: Да, существуют компиляторы различных языков в JS, такие как ScalaJS, PyJS и другие. Но стоит помнить, что у них есть масса недостатков и использовать их стоит только если на чистом JS (также CS и TS) не получается писать совершенно. Они предназначены прежде всего для тяжёлых приложений вроде браузерных 3D игр в классических Front-end целях не очень удобны.

В: Я слышал про какой то WebAssembly, который заменит JS. Это правда? Что это такое?

О: Нет, неправда. WebAssembly (WASM) практически не имеет отношения к классическому Front-end. Это особая технология, позволяющая выполнять в браузере бинарный код, компилируемый из различных языков. Он предназаначен для выполнения в браузере тяжёлых приложений вроде трёхмерных онлайн-игр и никак не связан с привычными задачами JS. Более того, учитывая развитую инфраструктуру JS, множество фреймворков и библиотек на все случаи жизни, большое количество профессиональных разработчиков, огромное количество легаси-кода, выполнение WASM иных задач, не связанных с различными высокопроизводительными трёхмерными приложениям, видится невозможным. Кроме того, WASM не затрагивает серверную и мобильно-десктопную часть JavaScript, которые уже успели стать довольно популярными.

В: С чего начать изучение?

Материалы для изучения

Книги про JavaScript

Марейн Хавербек — «Выразительный JavaScript» — Вводная книга по JavaScript и программирование в целом.

Дэвид Фленеган — «JavaScript: Подробное руководство«

Дуглас Крокфорд «JavaScript: сильные стороны«

Стефанов С. — «JavaScript. Шаблоны«

Джон Резиг — «Секреты JavaScript ниндзя«

Николас Закас — «JavaScript. Оптимизация производительности«

Джон Резиг, Расс Фергюсон — «JavaScript для профессионалов«

Dr. Axel Rauschmayer — «Speaking JavaScript: An In-Depth Guide for Programmers«

Discover Meteor — Книга по Meteor.js — одному из самых лёгких и функциональных фреймворков.

М. Кантелон , М. Хартер — «Node.js в действии«

Кирилл Сухов — «Node.js. Путеводитель по технологии«

Дэвид Хэррон — «Node.js. Разработка серверных веб-приложений»

Тодд Мотто — «Учебник AngularJS«

Max P — «Курс по React.js для начинающих«

Эдди Османи — «Разработка Backbone.js приложений«

Эрл Каслдайн, Крэйг Шарки — «Изучаем JQuery«

Адам Фримен — «jQuery для профессионалов«

И не забываем читать официальную документацию для каждого фреймворка.

Онлайн сообщества

learn.javascript.ru — Самый главный русскоязычный сайт по JavaScript. Других таких подробных уроков не найти. Начинать строго с него.

node-center.ru — Второй по важности сайт. Ориентирован на Node.js, но мелькает материал и по Front-end. Сборник всей нужной информации, перевод официальной документации, список книг и ссылок.

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

nodeguide.ru — Большое количество переведённых статей по Node.js

Блоги и новостные ленты

dailyjs.com — DailyJS

weblog.bocoup.com — Bocoup Weblog

perfectionkills.com — Perfection Kills

reddit.com/r/javascript — subreddit на reddit.com

toddmotto.com — Todd Motto, Lead front-end @appsbroker. Developer Expert @google.

Онлайн курсы

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

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

CodeAcademy

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

Дает хорошее представление о замыканиях.

Прошёл курсы, прочитал книги и думаешь, что знаешь JS? Теперь изучи тонкости и особенности языка. Сделать это можно здесь — https://shamansir.github.io/JavaScript-Garden/

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

Спасибо автору! Пикабу позновательный.

Ещё вопрос: появилось же «IT сообщество» на пикабу, почему подобного рода посты не добавляют туда? @moderator, там всего два поста, а в моей ленте по тегам «web», «IT», «программирование» каждый день штук 10 новых.

спасибо за пост!очень нужная информация)

Node-center.ru сдох, есть ли подобие?

Eloquent JS просто огонь, читаю как раз сейчас) Хотя там для начального уровня скорее.

Читать ещё на Пикабу

Простыми словами о фреймворках⁠ ⁠

Всем привет, работаю java разработчиком последние 9 лет, хотел бы пояснить на максимально простом примере зачем нужны фреймворки и в чем их отличие от библиотек.

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

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

Часть кода переезжает в настройки или в иной форме становится декларативной. Приведу пример конфигурации одного из самых популярных java фреймворков Spring. Проект будет загружать из БД список пользователей и отдавать их «как есть» через REST апи:

application.yml — конфигурируем порт для апи и настройку подключения к бд:

server.port: 8080
spring.datasource.url: jdbc:postgresql://localhost:5432/mydb

В формате фреймворка объявляем репозиторий — компонент для получения записей о пользователях из таблицы БД:

interface UserRepository extends CrudRepository<User, Long> <>

В формате фреймворка объявляем эндпоинт — точку для подключения других сервисов к REST апи нашего проекта:

Теперь другие сервисы могут через апи нашего сервиса получить список пользователей из БД:

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

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

«А если изменить скорость открывания, то можно сделать самолетный движок»⁠ ⁠

«А если изменить скорость открывания, то можно сделать самолетный движок»

Первый опыт работы в 16 лет в IT⁠ ⁠

Я хотел изначально написать этот пост на хабре, но это скорее просто личное желание поделиться опытом, радостью и слить накопленное, чем информативная статья с моими анализами и выводами.

Я занимаюсь программированием с детства, а веб разработкой всего пару лет, но тем не менее собрал достаточно знаний, чтобы попробовать найти работку в IT. Оно знаете, было как-то лень и интересно одновременно, я люблю приключения и к тому же я собирался работать удалённо. Мой системник уже проситься на тот свет, иногда просто может не включиться, помогает передёрнуть ОЗУ и почистить от пыли и он снова работает (Кому интересно, p7p55le + i5 750, 8 gb DDR3 и две Radeon HD 5830). Апгрейдить там бессмысленно, нужно с нуля собирать. Не то что бы меня это сильно мотивировало, ну останусь без пк, жизнь же продолжается; но он не ломается к удивлению, заставляя меня угрожать кулаком в монитор и по клавиатуре, когда курсор останавливается, а IDE (От реактивных мозгов) вылетает.

Путь до оффера

Приблизительно начало февраля 2022. Тихонько себе листал вакансии на hh и habr карьере, откликался, получал отказы, решал тестовые (увы, тестовой зарплаты не было), но я остановлюсь на собесах. Хотя и там особо всё просто, коммерческого опыта нет, ты маленький, и вообще что ты тут забыл. Потому я продолжал откликаться уже по приколу, на middle даже, ну прокатит и круто.

Ивент от яндекса.

Осень 2022. Яндекс приглашает поучаствовать в соревновании YaCup 2022. До денежного приза вряд ли дойду, а вот пройти отбор на стажировку по упрощённой схеме, если попал в топ 50 уже не так уж и не возможно. Рвя жопу и нервы, я занял 36 место (в направлении фронтенд) и через неделю меня пригласили пройти удалённо отбор. Подробно не буду. Прошёл первый этап, на том конце были весёлые ребята и прикольные задачи (относительно простые, по этому не нервничал). На втором этапе меня встретил мужик который вероятно давно не ухаживал за своей растительностью на лице. За ним была доска, где я должен был бы решать задачи, но у меня была фора, однако я всё равно завалил. В яндекс я не попал (

Удача?

Февраль 2023. Вечерочком сижу и листаю вакансии на хабре и откликаюсь на «Typescript Lead». Странное название, просто Typescript и просто Lead. В описании написано «в поисках джуна», ну а кто я, чтобы не тригернуться на слово «джун». Через часок, уже полностью сонный, смотрю пишет мужик с этой вакансии, мол, вообще смотришь куда откликаешься. Я подумал, ну бывает, хотя это не hh и на кассира случайно тут не откликнешься. Проверяю отклики и всё ок. Он зовёт поболтать.

Первый разговор был без вебки, так что я не знал кто там. По голосу лет на 20. Попросил выполнить тестовое к завтрашнему дню и втирал какую-то дичь про тёплую атмосферу в команде и что-то ещё, я не помню, хотел спать. Тестовое было простенькое, но я всё равно потратил на него пол дня.

На «собесе» меня встретил бородатый мужик далеко не 20ти лет, а как оказалось почти сорока. Вебку тоже пришлось включить, переборов себя. Это был просто разговор по интересам, был только один тех. вопрос (что такое DI?) на который я нашёл много что ответить (мог бы больше, но моя речь не поспевает за моими мыслями, я вообще довольно не общительный). Потом я ничего не помню, помню только конец. Через полтора часа разговора с меня уже стекли литры пота, пытаюсь сдерживать судороги в ногах и шею, которая тоже вот-вот пойдёт в разнос. Меня он оценил в 50к рублей и объявил испытательный срок — 3 месяца с 75% ставкой. Завершил разговор, требуя готовиться к первому рабочему дню. От меня он потребовал мой плейлист spotify, любимые фильмы, книги и moodboard, дабы «знать мой психотип», чтобы это не значило.

Надо сказать я устраивался на Frontend, он меня направил на FullStack и спойлер работал как Backend.

Первый рабочий день

Было так круто, что я аж в 6 утра подскочил. Меня добавили в телеграм группу по разработке. И к обеду мне прилетела задача (issue) в гитхаб. Единственное, что мне сказал руководитель — «Иди раскуривай».

Кстати про команду: руководитель(он же тот самый мужик), дизайнер(парень где-то лет 20ти) и два фронта, с которыми особо не контактировал.

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

Чтож. Делать нечего, я пишу, что-то вроде «памагите, я ничего не понимаю». Меня направили почитать про [куча терминов]. «Раскуриванием» задачи я занимался следующую неделю.

Из будущего: задача была в том, чтобы доить базы сети аптек по всей России, готовить данные и кормить ими с ложечки аналитические сервисы. Ведь просто, правда? Как будто я с базами данных не работал или бэкэндом. Но вот данных там на сотни гигабайт и это вполне тянет на биг дату. Обрабатывать их нужно грамотно, чтобы не было утечки памяти. А как это делать, я не знал.

Медленно, но уверенно

Я погружался в новые технологии, местный стек и так любимое в этом месте DDD. И вот первый потребитель данных доволен. Всё работает как надо, спустя сотни исправлений. И прошло уже чуть больше двух недель. Всё время я работал над проектом один, и настраивал его с полного нуля.

А вот и первая ЗП за 2 недели. Что кстати удивило, с самого начало думал, что кинут.

Отношение начинает меняться

На одном из one-to-one
— Ну как там?
— Первый потребитель готов, ещё два осталось
— Замечательно. За этот день добьёш?
— Нууу. Эээ.. Тут я думаю где-то к концу следующей недели доделаю.
— Б*ть, какой следующей недели. У нас уже сроки на этой недели заканчиваются. Чё там делать, то. Ты должен был по моим предположениям ещё на прошлой неделе всё сдать и перейти к следующему проекту.

Дальше на меня льётся куча критики и мата, а с моими то социальными навыками, я просто сижу как камень, слушаю, говорю «ага» и со всем соглашаюсь.

Что-то похожее происходило каждую неделю. «Ну чё за день осилишь», «Так, тогда через час идём в прод, да?», а там работы на неделю.

Затем мне пришло сообщение, что мой испытательный срок нужно продлить на ещё один месяц. Я поинтересовался, как это повлияет на ЗП. Оказалось всё нормально, на ЗП это продление не влияет. Держите это в голове, пригодится.

С проекта на проект

Сроки просрались, меня ведут на другой проект, а там прод лежит, и вообще что-то там наворотили и не работает, иду на следующий, через дня 2 всем говорят бросать этот проект и идти на другой.

Чтож на этот раз это бот для подготовки формы(pdf файла) для миграции в США. Он уже был готов, но там нужно было что-то «поправить». Пока я это правил, появились подробности, что оказывается там вообще сценарий вопросов не правильный. Ну ладно, сел переписывать. Ну и как обычно, я должен был сделать это вчера, а почему-то потратил на это три недели. Ну работает и ладно.

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

Последняя капля

Напоминаю, что частенько меня кроют в чате и one-to-one. Так, что мотивации и настроения, что-то делать у меня нет. Каждый день жду увольнения.

У меня есть такая особенность, что я копирую манеру общения собеседника. Так что отвечать добром на такие сообщения я не мог, а в one-to-one просто говорю «ага» и стараюсь как можно быстрее уйти, потому что такой разговор мне не приятен. Чтобы вы не думали, что я так всегда общаюсь, с дизайнером общаться вообще по кайфу, нет желания уйти, хотя и поддержать разговор также не получается.

На проекте с ботом у меня возникла проблема, с тем, что бот падает при создании pdf, но ошибки нет, точнее она пустая. Я обращаюсь к руководителю (больше не к кому)

— У меня не собирается pdf, падаёт ошибка в виде пустого объекта
. не помню точно, но разговор зашёл к тому, что зачем мне linux, если я им не умею пользоваться, и вообще — купи мак. Вот у тебя docker стартует из под рута, потому и не работает
— Слушай. Ну вот! Да! У меня всё собирается. Это у тебя Docker из под рута стартует.
— Ладно, буду разбираться.

Посидев, я понял в чём ошибка. И тут до меня доходит. Как он мог сгенерировать pdf, если ошибка совсем в другом. Я начал кое что подозревать, что уже давно подметил.

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

Ответ на один из моих глупых вопросов

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

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

Так, вот я решил проверить мою теорию(обращаясь к руководителю)

— А можно pdf который вчера удалось сгенерировать?
— [скидывает пустой pdf (бланк для заполнения)]
— Не, это бланк, мне нужно заполненный со вчера.
— Ты сказал не собирается, ну я и собрал. Генерация это уже другая задача.

И да. Я подтвердил свою теорию. Он придрался к термину. Я сказал «собрать», вместо «сгенерировать». Я окончательно сгорел, и назвал его душнилой, а потом не сдержался и ещё жёстче его покрыл. На что он ответил что-то вроде: что ты себе позволяешь, вы(команда), должны целовать мне ноги, я вам тут плачу, я собрал команду, я, я, я.

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

Саботаж

С этого момента, почти каждый день продолжалась эскалация конфликта. Я больше не задавал вопросов по задаче (поскольку от этого я только теряю время на бессмысленный токсичный разговор), и шёл на one-to-one только со словом «ага» и каменным лицом.

Одним утром, без настроения пытаясь разобрать очередную задачу, уже по другому проекту, я вылетаю из группы в телеграме. Я сначала не понял, что произошло, потом зашёл на github и увидел, что больше не состою в их организации. И я понял — я уволен. Однако в течении дня мне ничего не написали. Так, что это сделал я.

— Это типо увольнение? Тогда уж можно пожалуйста официальную причину и ЗП за 12 дней?
— Официальная причина — некомпетентность, саботаж
— Официально — ты у меня не работал, по документам, благо, не успел тебе контракт оформить. Я рекомендую тебе походить к врачу и начать общаться с людьми, у тебя большие проблемы, которые тебе предстоит решить.
— А зп за 12 дней? Если я получаю 50тр в месяц, то за 12 дней это должно быть 20тр
— Ты не получаешь 50к в месяц, я продлил твой испытательный, ты согласился

Поняли, да? Я там даже и не работал. И что ещё за «саботаж».

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

Вот такие мои весёлые приключения в мире трудоустройства в IT, так ещё и в 16 лет.

P.S. Ах, да. Мне хватило ровно на новый ПК. Так, что я не сильно расстроился.

Опять все забыли про мидлов⁠ ⁠

Опять все забыли про мидлов

Что не так с Шедеврумом и моя попытка это исправить⁠ ⁠

Недавно прокатилась волна о том, как Шедеврум от Яндекса замечательно рисует флаги США по запросу «наша родина», и меня, как специалиста, это сильно кольнуло. Настолько, что я решил что-то с этим сделать.

Вот пример такого художества, взял у Tagash, потому что уже закрыли костылем конкретно этот запрос, но основной проблемы это не решает:

Что не так с Шедеврумом и моя попытка это исправить Нейронные сети, Шедеврум (Яндекс), Программирование, Импортозамещение, IT, Длиннопост

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

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

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

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

Что не так с Шедеврумом и моя попытка это исправить Нейронные сети, Шедеврум (Яндекс), Программирование, Импортозамещение, IT, Длиннопост

(для названия решил скаламбурить: взял «AI» (Искусственный интеллект на английском), поменял буквы местами и получился ослик Иа. Не кидайте тапками за лого, это лучший осел, которого я осилил нарисовать, да и то через Dall-E 2).

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

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

Итак, как все это работает:

Нажимаем «Предложить ассоциацию». Система даст картинку для описания, которую кто-то ранее загрузил. Опишите одним словом, потом чуть подробнее и какие эмоции вызывает. Нажали на кнопку, описание улетело, получили следующую картинку и плюс в карму.

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

Что не так с Шедеврумом и моя попытка это исправить Нейронные сети, Шедеврум (Яндекс), Программирование, Импортозамещение, IT, Длиннопост

Неплохим примером описания было бы:
— Одним словом: лисы
— Подробнее: мама лиса с двумя лисятками, которые держатся за ее хвост на фоне травы
— Эмоции: милота, любопытсво (можно любой формат эмоций, прямо так как хочется сказать)

Кстати, если у вас есть желание помочь, то мне нужна юридическая помощь, а также с модерацией, разработкой, наполнением, да и вообще предложения приветствуются. Есть пара вопросов о том, как не угодить в «места не столь отдаленные» за инициативность)

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

А для братьев технарей — весь код лежит в открытом виде, все как положено.

Самая трешовая айти вакансия на HH обнаружена⁠ ⁠

Самая трешовая айти вакансия на HH обнаружена IT, Вакансии, Джуниор, Javascript, HH

Самая трешовая айти вакансия на HH обнаружена IT, Вакансии, Джуниор, Javascript, HH

Между прочим, компания расположена в г. Москва.

Парсинг персональных ачивок⁠ ⁠

Долгое время был в read-only, но на днях увидел пост о борьбе с баянами «своими» постами, и как бы сказать вдохновился. Ладушки, поехали.

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

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

Парсинг персональных ачивок Программирование, Награды Пикабу, Javascript, Длиннопост

На треугольники-стрелочки (которые слева) можно нажать, чтобы раскрыть список.

Парсинг персональных ачивок Программирование, Награды Пикабу, Javascript, Длиннопост

Отлично! Теперь можно скопировать ник пользователя, вставить в URL после «собачки» (https://pikabu.ru/@) и почитать посты.

Ну и сам скрипт с коментариями, если кто-то тоже хочет запустить у себя. Инструкция по запуску и проблемы ниже.

UPD. Не знал, что Пикабу не переваривает код. Ссылка на исходник https://pastebin.com/C7eZp3H7

Инструкция по запуску скрипта (только десктоп):

Открываем любую страницу Пикабу в браузере, лишь бы домен был pikabu.ru, иначе возможна ошибка CORS.

Нажимаем F12 (или Ctrl + Shift + i) (или тыкаем правой кнопкой мыши в любое место и выбираем пункт Inspect/Посмотреть код) (или через настройки браузера справа вверху в пункте Developer Tools/Инструменты разработчика). Открылись инструменты разработчика.

Открываем вкладку Console/Консоль.

Вставляем весь скрипт и нажимаем Enter.

Ждем секунд 40 (зависит от интернет соединения, к серверу же обращаемся). Можно посмотреть ход выполнения скрипта во вкладке Network/Сеть. Там должны запросы к серверу отличающиеся только параметром page.

Смотрим в консоль, и если ошибки нет, любуемся результатом.

Проблемы, с которыми столкнулся:

Только методом тыка удалось составить необходимый header для AJAX запроса. И почему-то это ‘X-Requested-With’. Странно, почему не ‘Content-Type’?

Кнопка «загрузить еще» грузит гребаный HTML код. Да, для браузера пользователя так быстрее, чем получать JSON и по нему рендерить HTML, но твою мать 🙁

Я с этим не сталкивался, но если кто-то хочет запустить скрипт у себя, возможны синтаксические ошибки, т.к. использовал такие конструкции как spread, window.fetch и async/await. Эта проблема решается свежей версией браузера, в которой должны быть реализованы эти фичи.

Почему-то на сервере всего 36 страниц наград. Т.е. это не все награды. Может и можно как-то загрузить все, но не нашел.

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

Странно, в предпросмотре поста, слетели табы/пробелы кода.

Ну вот и все. Сам скрипт занял примерно 2 часа, зато теперь можно почитать специфичные посты (жаль только что не все (см. п. 4 в проблемах)).

P.S. скрипт мой значит тег «мое» 🙂 Или нет, непонятно

P.P.S. чукча не писатель

Уже 9⁠ ⁠

Уже 9 IT, IT юмор, Картинка с текстом, Программирование, Javascript

Так можно и с Python играть⁠ ⁠

Так можно и с Python играть

У нас с JS есть общая тайна — мы оба не разбираемся в больших числах⁠ ⁠

У нас с JS есть общая тайна - мы оба не разбираемся в больших числах Разработка, Javascript, Json, IT юмор, Программирование

У нас с JS есть общая тайна - мы оба не разбираемся в больших числах Разработка, Javascript, Json, IT юмор, Программирование

P.S. JS не поддерживает целочисленные типы, все числа являются number, который по факту double, поэтому самый большой int который JS может сохранить без потери точности — 2^53 — 1

Никаких ошибок при попытке обработать слишком большое число не будет — оно просто сконвертируется в ближайшее представимое double (удачного дебага, если это ID в базе)

То же касается JSON — как формат, он не содержит точных требований как обрабатывать числа — всё number и зависит от имплементации. Какие-то языки и библиотеки различают int и double автомагически, какие-то всё интерпретируют как double, какие-то падают на конверсии.

Начальник взял в руки лопату⁠ ⁠

Начальник взял в руки лопату I`m CTO bitch, IT, Разработка, IT юмор, Программист, Программирование, Начальство, Fail, Раздолбайство, Стыд, Провал, Web-программирование, Опыт, Истории из жизни, Веб-разработка, Профессиональный юмор

Телеграм канал для тех, кому интересны другие мои приключения руководителя в IT.

Как я написал свою поисковую систему для быстрого поиска личной информации⁠ ⁠

Как я написал свою поисковую систему для быстрого поиска личной информации Поиск, Web-программирование, Программирование, Поисковик, Поисковые системы, Поисковые запросы, IT, Длиннопост, Теги

Предыстория

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

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

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

Более того по содержанию можно искать только текстовые файлы.

Структура содержания информации

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

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

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

А почему бы об этом просто не попросить прихвостня(они уже у всех есть, правда?) -«Принеси мне зелёное свежее яблоко».

Как сразу становится удобно!

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

А вот если мы не знаем существуют ли яблоки вообще, то спрашиваем прихвостня:

— «Есть, господин! Сотни, игрушечные, красные, гнилые..».

— «Мне нужно свежее яблоко».

— «Понял! Есть красное свежее яблоко «Сирота», красное свежее яблоко «курага». «.

— «А что насчёт зелёного свежего яблока».

— «Есть! Зелёное свежее яблоко «Пух-тибидух» и Зелёное свежее яблоко «Девственный»».

— «В таком случае, принеси мне, пожалуй, Зелёное свежее яблоко «Девственный»».

Вот последняя фраза как раз таки и стала названием приложения. Как ответ на команду пользователя — «Yes Sir».

Возвращаясь к яблокам. Заметили, что в первом случае нужно искать яблоки не пойми где, а во втором мы задаём уточняющие условия к запросу!?

Как я написал свою поисковую систему для быстрого поиска личной информации Поиск, Web-программирование, Программирование, Поисковик, Поисковые системы, Поисковые запросы, IT, Длиннопост, Теги

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

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

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

В этом случае возможно группировать, сортировать музыку гораздо гибче. Например скомбинировав 3 тега: французская, русская, рок можно получить то, чего стандартными средствами Windows не возможно, ну или я чего-то не знаю.

Попытки найти готовое решение.

Первой идеей было воспользоваться «тегированием» файлов, папок. Таким образом можно искать информацию комбинируя теги, не зависимо от порядка слов. И лучшими приложениями для этого, могу выделить XYplorer и Tagging for windows. Первая из себя представляет отдельный файловый менеджер с опцией тегирования. Второе приложение — дополнение к стандартному файловому менеджеру. Однако они позволяют искать файлы только на ПК и конечно нельзя написать как в Гугл поисковике запрос близкий к пользователю, а алгоритм уже бы сам выбрал из запроса теги и отсортировал информацию по приоритету. В последствии удалил обе, они подвисали и крашились частенько (возможно дело в моих надстройках Windows, не хочу делать антипиар этих отличных программ).

Визуальный поиск

В попытках найти оптимальный способ поиска доходило до странного. Я больше визуал и поэтому загружал изображения более менее подходящее по теме информации в социальную сеть ВКонтакте, а саму информацию сохранял в комментариях под изображениями. Это дало некоторый прирост в скорости поиска и пользоваться можно с любого устройства. Но как вы, наверное, понимаете долго это продолжаться не могло. В конечном итоге я стал задумываться а к какой информации относится это изображение : «Рельсы означает адреса знакомых или желаемые места для путешествия..». Ну а уж то, что под одним изображением образуется портянка из информации без возможности вложенности — это фиаско, бро.

Я подумал, что было бы отлично разработать приложение, которое бы подходило по таким критериям:

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

2. Поиск личной информации настолько быстро, насколько это возможно.

3. Поиск должен быть простым как Google Search.

4. Возможность сохранить всю текстовую информацию в текстовый файл.

Выбор технологий

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

Для синхронизации данных с другим устройством, браузером я взял базу данных mysql от 000webhost бесплатно, но потом перестал использовать из-за ограничений на обьем.

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

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

2. Быстрый поиск.

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

Итак по ключу «теги» у нас будет храниться массив из символов(слов) для конкретного блока информации.

Сразу возьмём пример блока:

Название: как создать сайт,

Действие: показать информацию,

Содержимое: берём html, добавляем js и украшаем css,

Теги: создание сайта, веб программирование, верстка.

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

Из примера блока выше массив тегов будет таким: [«как», «создать», «сайт», «создание», «сайта», «веб» «программирование», «верстка»]

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

3. Итак, при вводе запроса проверяется существует ли слово в хранилище тегов, если да, то блок добавляется в массив на отображение.

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

4. И насчёт сохранение в файл совсем кратко. Можно сохранять и импортировать файл в виде json.

Так же мой опыт с использованием ВКонтакте как поисковик по изображениям дал мне идею для возможности добавлять изображение к каждому блоку при желании.

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

Ответвление в другие проекты

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

Послесловие

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

Основы JavaScript

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

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

2. Основы синтаксиса

2.1. Инструкции

Код JavaScript состоит из инструкций, каждая из которых завершается точкой запятой:

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

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

2.2. Комментарии

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

Комментарии могут быть однострочными, для которых используется двойной слэш // :

Кроме однострочных комментариев могут использоваться и многострочные комментарии. Такие комментарии заключаются между символами /* текст комментария */ . Например:

2.3. Переменные

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

Для создания переменных применяются ключевые слова var и let . Например, объявим переменную myIncome :

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

Например, правильные названия переменных:

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

Также нельзя давать переменным такие имена, которые совпадают с зарезервированными ключевыми словами. В JavaScript не так много ключевых слов, поэтому данное правило несложно соблюдать. Например, следующее название будет некорректным, так как for — ключевое слово в JavaScript:

Список зарезервированных слов в JavaScript:

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

Через запятую можно определить сразу несколько переменных:

С помощью знака равно = можно присвоить переменной какое-либо значение:

Процесс присвоения переменной начального значения называется инициализацией. Теперь переменная income будет хранить число 300 , а переменная price — число 76 . Отличительной чертой переменных является то, что можно изменить их значение:

2.4. Константы

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

Если попробовать изменить ее значение, то возникнет ошибка:

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

2.5. Типы данных

Все используемые данные в JavaScript имеют определенный тип. В JavaScript имеется пять примитивных типов данных:

String : представляет строку

Number : представляет числовое значение

Boolean : представляет логическое значение true или false

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

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

Все данные, которые не попадают под вышеперечисленные пять типов, относятся к типу object .

2.5.1. Числовые данные

Числа в JavaScript могут иметь две формы:

Целые числа, например, 35 . Можно использовать как положительные, так и отрицательные числа. Диапазон используемых чисел: от -2^53 до 2^53 .

Дробные числа (числа с плавающей точкой), например, 3.5575 . Опять же можно использовать как положительные, так и отрицательные числа. Для чисел с плавающей точкой используется тот же диапазон: от -2^53 до 2^53 .

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

2.5.2. Строки

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

Единственно ограничение: тип закрывающей кавычки должен быть тот же, что и тип открывающей, то есть либо обе двойные, либо обе одинарные кавычки.

Если внутри строки встречаются кавычки, то их нужно экранировать слэшем \ . Например, пусть у нас есть текст Бюро «Рога и копыта» . Теперь экранируем кавычки:

Также можно внутри стоки использовать другой тип кавычек:

2.5.3. Тип Boolean

Тип Boolean представляет булевы или логические значения true и false (то есть да или нет):

2.5.4. null и undefined

Нередко возникает путаница между null и undefined . Итак, когда только определяется переменная без присвоения ей начального значения, она представляет тип undefined :

Присвоение значение null означает, что переменная имеет некоторое неопределенное значение (не число, не строка, не логическое значение), но все-таки имеет значение. undefined означает, что переменная не имеет значения.

2.5.5. object

Тип object представляет сложный объект. Простейшее определение объекта представляют фигурные скобки:

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

В данном случае объект называется user , и он имеет два свойства: name и age . Это краткое описание объектов.

2.5.6. Слабая типизация

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

Несмотря на то, что во втором и третьем случае консоль выведет число 45 , но во втором случае переменная xNumber будет представлять число, а в третьем случае — строку.

Это важный момент, который надо учитывать. От этого зависит поведение переменной в программе:

Выше в обоих случая к переменной xNumber применяется операция сложения + . Но в первом случае xNumber представляет число, поэтому результатом операции xNumber + 5 будет число 50 .

Во втором случае xNumber представляет строку. Но операция сложения между строкой и числом 5 невозможна. Поэтому число 5 будет преобразовываться к строке, и будет происходить операция объединения строк. И результатом выражения xNumber + 5 будет стока «455» .

2.6. Операторы

2.6.1. Оператор typeof

С помощью оператора typeof можно получить тип переменной:

2.6.2. Математические операторы

JavaScript поддерживает все базовые математические операции:

Сложение:

Вычитание:

Умножение:

Деление:

Деление по модулю (оператор % ) возвращает остаток от деления:

Результатом будет 5 , так как наибольшее целое число, которое меньше или равно 40 и при этом делится на 7 равно 35 , а 40 — 35 = 5 .

Инкремент

Оператор инкремента ++ увеличивает переменную на единицу. Существует префиксный инкремент, который сначала увеличивает переменную на единицу, а затем возвращает ее значение:

И есть постфиксный инкремент, который сначала возвращает значение переменной, а затем увеличивает его на единицу:

Постфиксный инкремент аналогичен операции:

Декремент

Декремент уменьшает значение переменной на единицу. Также есть префиксный и постфиксный декремент:

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

2.6.3. Операции присваивания

=
Приравнивает переменной определенное значение: var x = 5 ;

+=
Сложение с последующим присвоением результата.

-=
Вычитание с последующим присвоением результата.

*=
*Умножение* с последующим присвоением результата:

/=
Деление с последующим присвоением результата:

%=
Получение остатка от деления с последующим присвоением результата:

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

Как правило, для проверки условия используются операторы сравнения. Операторы сравнения сравнивают два значения и возвращают значение true или false :

==
Оператор равенства сравнивает два значения, и если они равны, возвращает true , иначе возвращает false : x == 5

===
Оператор тождественности также сравнивает два значения и их тип, и если они равны, возвращает true , иначе возвращает false : x === 5

!=
Сравнивает два значения, и если они не равны, возвращает true , иначе возвращает«false`: x != 5

!==
Сравнивает два значения и их типы, и если они не равны, возвращает true , иначе возвращает false : x !== 5

>
Сравнивает два значения, и если первое больше второго, то возвращает true , иначе возвращает false : x > 5

<
Сравнивает два значения, и если первое меньше второго, то возвращает true , иначе возвращает false : x < 5

>=
Сравнивает два значения, и если первое больше или равно второму, то возвращает true , иначе возвращает false : x >= 5

<=
Сравнивает два значения, и если первое меньше или равно второму, то возвращает true , иначе возвращает false : x <= 5

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

Переменная result здесь будет равна true , так как фактически и income , и strIncome представляют число 100 .

Но оператор тождественности возвратит в этом случае false , так как данные имеют разные тип:

Аналогично работают операторы неравенства != и !== .

2.6.5. Логические операции

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

&&
Возвращает true , если обе операции сравнения возвращают true , иначе возвращает false :

||
Возвращает true , если хотя бы одна операция сравнения возвращают true , иначе возвращает false :

!
Возвращает true , если операция сравнения возвращает false :

2.6.6. Операции со строками

Строки могут использовать оператор + для объединения.

Если одно из выражений представляет строку, а другое — число, то число преобразуется к строке и выполняется операция объединения строк:

2.6.7. Пример

Программа, которая продемонстрирует работу с операциями над переменными.

В скрипте объявляются три переменных: sum , percent и income . Переменная income вычисляется по остальным двум переменным с помощью операций умножения и деления. И в конце ее значение суммируется со значением переменной sum .

И консоль браузера выведет:

Результат операций с переменными

2.7. Преобразование данных

Нередко возникает необходимость преобразовать одни данные в другие. Например:

Обе переменных представляют строки, а точнее строковые представления чисел. И в итоге получим не число 50 , а строку 464 . Но было бы неплохо, если бы их тоже можно было бы складывать, вычитать, в общем работать как с обычными числами.

В этом случае можно использовать операции преобразования. Для преобразования строки в число применяется функция parseInt() :

Для преобразования строк в дробные числа применяется функция parseFloat() :

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

Если методу не удастся выполнить преобразование, то он возвращает значение NaN (Not a Number), которое говорит о том, что строка не представляет число и не может быть преобразована.

С помощью специальной функции isNaN() можно проверить, представляет ли строка число. Если строка не является числом, то функция возвращает true , если это число — то false :

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

Результатом будет 6 , так как 110 в двоичной системе — это число 6 в десятичной.

2.7.1. Пример

Теперь напишем небольшую программу, в которой используем операции с переменными:

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

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

После открытия страницы в браузере увидим приглашение к вводу суммы вклада:

приглашение к вводу суммы

Затем подобное сообщение отобразится и для ввода процента. И в конце программа получит данные, преобразует их в числа и выполнит подсчет:

результаты подсчета

2.8. Массивы

Для работы с наборами данных предназначены массивы. Для создания массива применяется выражение new Array() :

Существует также более короткий способ инициализации массива:

В данном случае создаётся пустой массив. Но можно также добавить в него начальные данные:

В этом случае в массиве myArray будет три элемента. Его можно представить в виде таблицы так:

Для обращения к отдельным элементам массива используются индексы. Отсчет начинается с нуля, то есть первый элемент будет иметь индекс 0, а последний — 2:

Если попробовать обратиться к элементу по индексу больше размера массива, то получим undefined :

Также по индексу осуществляется установка значений для элементов массива:

Причем в отличие от других языков, как Java или C#, можно установить элемент, который изначально не установлен:

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

2.8.1. spread-оператор

spread-оператор …​ позволяет взять значения из массива по отдельности:

spread-оператор указывается перед массивом. В результате выражение …​numbers возвратит набор чисел, но это будет не массив, а именно отдельные значения.

2.8.2. Многомерные массивы

Массивы могут быть одномерными и многомерными. Каждый элемент в многомерном массиве может представлять собой отдельный массив. Выше рассмотрели одномерный массив, теперь создадим многомерный массив:

Визуально оба массива можно представить следующим образом:

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

Рассмотрим еще один двумерный массив:

Массив people можно представить в виде следующей таблицы:

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

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

То есть если визуально двумерный массив можно представить в виде таблицы, то элемент people[0][1] будет ссылаться на ячейку таблицы, которая находится на пересечении первой строки и второго столбца (первая размерность — 0 — строка, вторая размерность — 1 — столбец).

Также можно выполнить присвоение:

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

2.9. Условные конструкции

Условные конструкции позволяют выполнить те или иные действия в зависимости от определенных условий.

2.9.1. Выражение if

Конструкция if проверяет некоторое условие и если это условие верно, то выполняет некоторые действия. Общая форма конструкции if :

Здесь в конструкции if используется следующее условие: income > 50 . Если это условие возвращает true , то есть переменная income имеет значение больше 50 , то браузер отображает сообщение. Если же значение income меньше 50 , то никакого сообщения не отображается.

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

Причем условия могут быть сложными:

Конструкция if позволяет проверить наличие значения.

Если переменная myVar имеет значение, то в условной конструкции она возвратит значение true .

Но нередко для проверки значения переменной используют альтернативный вариант — проверяют на значение undefined :

В конструкции if также можно использовать блок else . Данный блок содержит инструкции, которые выполняются, если условие после if ложно, то есть равно false :

С помощью конструкции else if можно добавить альтернативное условие к блоку if :

В данном случае выполнится блок else if . При необходимости можно использовать несколько блоков else if с разными условиями:

2.9.2. true или false

В JavaScript любая переменная может применяться в условных выражениях, но не любая переменная представляет тип boolean . Поэтому возникает вопрос, что возвратит та или иная переменная — true или false ? Много зависит от типа данных, который представляет переменная:

undefined
Возвращает false

null
Возвращает false

Boolean
Если переменная равна false , то возвращается false . Соответственно, если переменная равна true , то возвращается true

Number
Возвращает false , если число равно 0 или NaN (Not a Number), в остальных случаях возвращается true

String
Возвращает false , если переменная равна пустой строке, то есть ее длина равна 0, в остальных случаях возвращается true

Object
Всегда возвращает true

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

Конструкция switch..case является альтернативой использованию конструкции if..else if..else и также позволяет обработать сразу несколько условий:

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

В конце каждого блока сase ставится оператор break , чтобы избежать выполнения других блоков.

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

2.9.4. Тернарная операция

Тернарная операция состоит из трех операндов и имеет следующее определение:

[первый операнд — условие] ? [второй операнд] : [третий операнд]

В зависимости от условия тернарная операция возвращает второй или третий операнд: если условие равно true , то возвращается второй операнд; если условие равно false , то третий. Например:

Если значение переменной a меньше значения переменной b , то переменная result будет равняться a + b . Иначе значение result будет равняться a — b .

2.10. Циклы

Циклы позволяют в зависимости от определенных условий выполнять некоторое действие множество раз. В JavaScript имеются следующие виды циклов:

2.10.1. Цикл for

Цикл for имеет следующее формальное определение:

Например, используем цикл for для перебора элементов массива:

Первая часть объявления цикла — var i = 0 — создает и инициализирует счетчик — переменную i . И перед выполнением цикла ее значение будет равно 0 . По сути это то же самое, что и объявление переменной.

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

Третья часть — приращение счетчика на единицу.

И так как в массиве 4 элемента, то блок цикла сработает 4 раза, пока значение i не станет равным people.length (то есть 4 ). И каждый раз это значение будет увеличиваться на 1. Каждое отдельное повторение цикла называется итерацией. Таким образом, в данном случае сработают 4 итерации.

А с помощью выражения people[i] можно получить элемент массива для его последующего вывода в браузере.

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

В данном случае массив выводится с конца, а перебор массива начинается с i = 3 до i = 0 .

2.10.2. Цикл for..in

Цикл for..in предназначен для перебора массивов и объектов. Его формальное определение:

Например, переберем элементы массива:

2.10.3. Цикл for…​of

Цикл for…​of похож на цикл for…​in и предназначен для перебора коллекций, например, массивов:

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

2.10.4. Цикл while

Цикл while выполняется до тех пор, пока некоторое условие истинно. Его формальное определение:

Опять же выведем с помощью while элементы массива:

Цикл while здесь будет выполняться, пока значение index не станет равным длине массива.

2.10.5. Цикл do..while

В цикле do сначала выполняется код цикла, а потом происходит проверка условия в инструкции while . И пока это условие истинно, цикл повторяется. Например:

Здесь код цикла сработает 9 раз, пока x не станет равным 10 . При этом цикл do гарантирует хотя бы однократное выполнение действий, даже если условие в инструкции while не будет истинно.

2.10.6. Операторы continue и break

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

Данный цикл перебирает все элементы массива, однако последние четыре элемента не будут выведены в браузере, поскольку поверка if (array[i] > 10) прервет выполнение цикла с помощью оператора break , когда перебор массива дойдет до элемента 12 .

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

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

3. Функциональное программирование

3.1. Функции

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

Синтаксис определения функции:

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

После имени функции в скобках идет перечисление параметров. Даже если параметров у функции нет, то просто идут пустые скобки. Затем в фигурных скобках идет тело функции, содержащее набор инструкций.

Определим простейшую функцию:

Данная функция называется display() . Она не принимает никаких параметров и все, что она делает, это пишет на web-страницу строку.

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

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

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

Также можно динамически присваивать функции для переменной:

3.1.1. Параметры функции

Рассмотрим передачу параметров:

Функция display принимает один параметр — x . Поэтому при вызове функции можно передать для него значение, например, число 5 , как в данном случае.

Если функция принимает несколько параметров, то с помощью spread-оператора …​ можно передать набор значений для этих параметров из массива:

Во втором случае в функцию передается числа из массива nums . Но чтобы передавался не просто массив, как одно значение, а именно числа из этого массива, применяется spread-оператор …​ .

3.1.2. Необязательные параметры

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

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

Есть и другой способ определения значения для параметров по умолчанию:

Если параметрам x и y не передаются значения, то они получаются в качестве значений числа 5 и 10 соответственно. Такой способ более лаконичен и интуитивен, чем сравнение с undefined .

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

В данном случае значение параметра y зависит от значения x .

При необходимости можно получить все переданные параметры через глобально доступный массив arguments :

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

3.1.3. Неопределенное количество параметров

С помощью spread-оператора можно указать, что с помощью параметра можно передать переменное количество значений:

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

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

3.1.4. Результат функции

Функция может возвращать результат. Для этого используется оператор return :

После оператора return идет значение, которое надо возвратить из метода. В данном случае это квадрат числа х .

После получения результата функции можно присвоить его какой-либо другой переменной:

3.1.5. Функции в качестве параметров

Функции могут выступать в качестве параметров других функций:

Функция operation принимает три параметра: x , y и func . func — представляет функцию, причем на момент определения operation не важно, что это будет за функция. Единственное, что известно, что функция func может принимать два параметра и возвращать значение, которое затем отображается в консоли браузера. Поэтому можно определить различные функции (например, функции sum и subtract в данном случае) и передавать их в вызов функции operation .

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

Одна функция может возвращать другую функцию:

В данном случае функция menu в зависимости от переданного в нее значения возвращает одну из трех функций или undefined .

3.2. Область видимости переменных

Все переменные в JavaScript имеют определенную область видимости, в пределах которой они могут действовать.

3.2.1. Глобальные переменные

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

Здесь переменные x и d являются глобальными. Они доступны из любого места программы. А вот переменная z глобальной не является, так как она определена внутри функции.

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

Переменная, определенная внутри функции, является локальной:

Переменные z и b являются локальными, они существуют только в пределах функции. Вне функции их нельзя использовать:

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

3.2.3. Сокрытие переменных

Что если у нас есть две переменных — одна глобальная, а другая локальная, которые имеют одинаковое имя:

В этом случае в функции будет использоваться та переменная z , которая определена непосредственно в функции. То есть локальная переменная скроет глобальную переменную.

3.2.4. var или let

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

Здесь внутри функции displayZ() определен блок кода, в котором определена переменная z . Она скрывает глобальную переменную и переменную z , определенную на уровне функции. В реальной программе блок мог быть предоставлять вложенную функцию, блок цикла for или конструкции if . Но в любом случае такой блок определяет новую область видимости, вне которого переменная не существует.

И в данном случае получим следующий консольный вывод:

С помощью оператора var можно определить одновременно переменную с одним и тем же именем и в функции, и в блоке кода в этой функции:

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

3.2.5. Константы

Все, что относится к оператору let , относится и к оператору const , который позволяет определить константы. Блоки кода задают область видимости констант, а константы, определенные на вложенных блоках кода, скрывают внешние константы с тем же именем:

3.2.6. Необъявленные переменные

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

Несмотря на то, что вне функции bar переменная foo нигде не определяется, тем не менее она доступна вне функции во внешнем контексте.

Иначе, если не только присвоить значение переменной, но и переопределить ее:

3.2.7. strict mode

Определение глобальных переменных в функциях может вести к потенциальным ошибкам. Чтобы их избежать используется строгий режим или strict mode:

Установить режим strict mode можно двумя способами:

Добавить выражение «use strict» в начало кода `JavaScript, тогда strict mode будет применяться для всего кода.

Добавить выражение «use strict» в начало тела функции, тогда strict mode будет применяться только для этой функции.

3.3. Замыкания

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

Замыкание технически включает три компонента:

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

Переменные (лексическое окружение), которые определены во внешней функции

Вложенная функция, которая использует эти переменные

3.3.1. Пример

Рассмотрим замыкания на простейшем примере:

Здесь функция outer задает область видимости, в которой определены внутренняя функция inner и переменная x . Переменная x представляет лексическое окружение для функции inner . В самой функции inner инкрементируем переменную x и выводим ее значение на консоль. В конце функция outer возвращает функцию inner .

Далее вызываем функцию outer :

Поскольку функция outer возвращает функцию inner , то переменная fn будет хранить ссылку на функцию inner . При этом эта функция запомнила свое окружение — то есть внешнюю переменную x .

Далее фактически три раза вызываем функцию Inner , и видно, что переменная x , которая определена вне функции inner , инкрементируется:

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

3.3.2. Пример

Рассмотрим следующий пример:

Итак, здесь вызов функции multiply() приводит к вызову другой внутренней функции. Внутренняя же функция:

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

В итоге при вызове функции multiply определяется переменная fn1 , которая и представляет собой замыкание, то есть объединяет две вещи: функцию и окружение, в котором функция была создана. Окружение состоит из любой локальной переменной, которая была в области действия функции multiply во время создания замыкания.

То есть fn1 — это замыкание, которое содержит и внутреннюю функцию function(m) < return x * m;>, и переменную x , которая существовала во время создания замыкания.

При создании двух замыканий: fn1 и fn2 , для каждого из этих замыканий создается свое окружение.

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

Число 5 передается для параметра n функции multiply .

При вызове внутренней функции:

Число 6 передается для параметра m во внутреннюю функцию function(m) < return x * m;>; .

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

3.4. Функции IIFE (Самовызывающиеся функции)

Обычно определение функции отделяется от ее вызова: сначала определяем функцию, а потом вызываем. Но это необязательно. Также можем создать такие функции, которые будут вызываться сразу при определении. Такие функции еще называют Immediately Invoked Function Expression (IIFE).

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

3.5. Паттерн Модуль

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

Определим простейший модуль:

Здесь определена переменная foo , которая представляет результат анонимной функции. Внутри подобной функции определен объект obj с некоторыми данными.

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

Такая конструкция позволяет закрыть некоторый набор данных в рамках функции-модуля и опосредовать доступ к ним через определенный API — возвращаемые внутренние функции.

Рассмотрим чуть более сложный пример:

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

Все данные сокрыты в объекте data , который хранит результат операции. Все операции представлены тремя возвращаемыми функциями: sum() , subtract() и display() . Через эти функции можно управлять результатом калькулятора извне.

3.6. Рекурсивные функции

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

Например, рассмотрим функцию, определяющую факториал числа:

Функция getFactorial() возвращает значение 1, если параметр n равен 1 , либо возвращает результат опять же функции getFactorial , то в нее передается значение n-1 . Например, при передаче числа 4 , у нас образуется следующая цепочка вызовов:

Рассмотрим другой пример — определение чисел Фибоначчи:

3.7. Переопределение функций

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

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

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

Здесь переменная displayMessage получает ссылку на функцию display() до ее переопределения. Поэтому при вызове displayMessage() будет вызываться не переопределенная версия функции display .

Но допустим, определили переменную displayMessage уже после вызова функции display() :

В этом случае переменная displayMessage будет указывать на переопределенную версию функции display() .

3.8. Hoisting

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

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

Переменные, которые попадают под hoisting, получают значение undefined .

Например, возьмем следующий простейший код:

Его выполнение вызовет ошибку

Добавим определение переменной:

В этом случае консоль выведет значение undefined . При первом проходе компилятор узнает про существование переменной foo . Она получает значение undefined . При втором проходе вызывается метод console.log(foo) .

Возьмем другой пример:

Здесь та же ситуация. Переменные a и b используются до определения. По умолчанию им присваиваются значения undefined . А если умножить undefined на undefined , то получим Not a Number ( NaN ).

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

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

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

В данном случае получим ошибку

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

Поэтому при определении переменных и функций следует учитывать такой аспект как hoisting.

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

3.9.1. Передача параметров по значению

Строки, числа, логические значения передаются в функцию по значению. Иными словами при передаче значения в функцию, эта функция получает копию данного значения. Рассмотрим, что это значит в практическом плане:

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

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

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

В данном случае функция change получает объект и меняет его свойство name . В итоге увидим, что после вызова функции изменился оригинальный объект bob , который передавался в функцию.

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

То же самое касается массивов:

3.10. Стрелочные функции

Стрелочные функции (arrow functions) представляют сокращенную версию обычных функций. Стрелочные функции образуются с помощью знака стрелки => , перед которым в скобках идут параметры функции, а после — собственно тело функции.

В данном случае функция (x, y) => x + y осуществляет сложение двух чисел и присваивается переменной sum . Функция принимает два параметра — x и y . Ее тело составляет сложение значений этих параметров. И поскольку после стрелки фактически идет конкретное значение, которое представляет сумму чисел, то функция возвращает это значение. И можно через переменную sum вызвать данную функцию и получить ее результат в переменные a и b .

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

В данном случае функция console.log() ничего не возвращает, и соответственно функция sum также не возвращает никакого результата.

Если функция принимает один параметр, то скобки вокруг него можно опустить:

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

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

Особо следует остановиться на случае, когда стрелочная функция возвращает объект:

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

Если стрелочная функция не принимает никаких параметров, то ставятся пустые скобки:

4. Реализация ООП в JavaScript

4.1. Объекты

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

4.1.1. Создание нового объекта

Есть несколько способов создания нового объекта.

Первый способ заключается в использовании конструктора Object :

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

Выражение new Object() представляет вызов конструктора — функции, создающей новый объект. Для вызова конструктора применяется оператор new . Вызов конструктора фактически напоминает вызов обычной функции.

Второй способ создания объекта представляет использование фигурных скобок:

Более распространенным является второй способ создания объекта.

4.1.2. Свойства объекта

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

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

Также можно определить свойства при определении объекта:

В этом случае для присвоения значения свойству используется символ двоеточия, а после определения свойства ставится запятая (а не точка с запятой).

Кроме того, доступен сокращенный способ определения свойств:

4.1.3. Методы объекта

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

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

Также методы могут определяться непосредственно при определении объекта:

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

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

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

4.1.4. Синтаксис массивов

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

Название каждого свойства или метода заключается в кавычки и в квадратные скобки, затем им также присваивается значение. Например, user[«age»] = 26 .

При обращении к этим свойствам и методам можно использовать либо нотацию точки user.name , либо обращаться так: user[«name»] .

4.1.5. Строки в качестве свойств и методов

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

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

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

4.1.6. Удаление свойств

Удалять свойства и методы необходимо с помощью оператора delete . Как и в случае с добавлением удалять свойства можно двумя способами. Первый способ — использование нотации точки:

Либо использовать синтаксис массивов:

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

4.2. Вложенные объекты и массивы в объектах

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

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

Либо обращаться к ним как к элементам массивов:

Также допустим смешанный вид обращения:

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

В объекте country имеется свойство languages, содержащее массив строк, а также свойство cities , хранящее массив однотипных объектов.

С этими массивами можно работать так же, как и с любыми другими, например, перебрать с помощью цикла for .

При переборе массива объектов каждый текущий элемент будет представлять отдельный объект, поэтому мы можем обратиться к его свойствам и методам:

4.3. Проверка наличия и перебор методов и свойств

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

Оператор in имеет следующий синтаксис: «свойство|метод» in объект — в кавычках идет название свойства или метода, а после in — название объекта. Если свойство или метод с подобным именем имеется, то оператор возвращает true . Если нет — то возвращается false .

Альтернативный способ заключается на значение undefined . Если свойство или метод равен undefined , то эти свойство или метод не определены:

И так как объекты представляют тип Object , а значит, имеет все его методы и свойства, то объекты также могут использовать метод hasOwnProperty() , который определен в типе Object :

4.3.1. Перебор свойств и методов

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

4.4. Объекты в функциях

Функции могут возвращать значения. Но эти значения необязательно должны представлять примитивные данные — числа, строки, но также могут быть сложными объектами.

Например, вынесем создание объекта user в отдельную функцию:

Здесь функция createUser() получает значения pName и pAge и по ним создает новый объект, который является возвращаемым результатом.

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

Кроме того объект может передаваться в качестве параметра в функцию:

4.5. Конструкторы объектов

Кроме создания новых объектов JavaScript предоставляет возможность создавать новые типы объектов с помощью конструкторов. Так, одним из способов создания объекта является применение конструктора типа Object :

После создания переменной tom она будет вести себя как объект типа Object .

Конструктор позволяет определить новый тип объекта. Можно еще провести следующую аналогию.

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

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

Чтобы вызвать конструктор, то есть создать объект типа User , надо использовать ключевое слово new :

4.5.1. Оператор instanceof

Оператор instanceof позволяет проверить, с помощью какого конструктора создан объект. Если объект создан с помощью определенного конструктора, то оператор возвращает true :

4.6. Расширение объектов. Prototype

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

Например, после определения объекта User необходимо добавить к нему метод и свойство:

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

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

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

Но есть возможность их скрыть от доступа извне, сделав свойства локальными переменными:

В конструкторе User объявляется локальная переменная _age вместо свойства age . Как правило, названия локальных переменных в конструкторах начинаются со знака подчеркивания.

Для того, что бы работать с возрастом пользователя извне, определяются два метода. Метод getAge() предназначен для получения значения переменной _age . Этот метод еще называется геттер (getter). Второй метод — setAge , который еще называется сеттер (setter), предназначен для установки значения переменной _age .

4.8. Функция как объект. Методы call() и apply()

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

Например, мы можем создать функцию с помощью конструктора Function :

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

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

arguments : массив аргументов, передаваемых в функцию

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

caller : определяет функцию, вызвавшую текущую выполняющуюся функцию

name : имя функции

prototype : прототип функции

С помощью прототипа можно определить дополнительные свойства:

Среди методов надо отметить методы call() и apply() .

Метод call() вызывает функцию с указанным значением this и аргументами:

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

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

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

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

4.9. Наследование

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

В конструкторе Employee происходит обращение к конструктору User с помощью вызова:

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

Кроме того, необходимо унаследовать также и прототип User . Для этого служит вызов:

Метод Object.create() позволяет создать объект прототипа User , который затем присваивается прототипу Employee . При этом при необходимости в прототипе Employee мы также можем определить дополнительные свойства и методы.

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

4.10. Ключевое слово this

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

4.10.1. Глобальный контекст

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

4.10.2. Контекст функции

В пределах функции this ссылается на внешний контекст. Для функций, определенных в глобальном контексте, — это объект Window , который представляет окно браузера.

Если не использовать this , то обращение шло бы к локальной переменной, определенной внутри функции.

Но если использовать строгий режим (strict mode), то this в этом случае имело бы значение undefined :

4.10.3. Контекст объекта

В контексте объекта, в том числе в его методах, ключевое слово this ссылается на этот же объект:

4.10.4. Явная привязка

С помощью методов call() и apply() можно задать явную привязку функции к определенному контексту:

4.10.5. Метод bind

Метод f.bind(o) позволяет создать новую функцию с тем же телом и областью видимости, что и функция f() , но с привязкой к объекту o :

4.10.6. this и стрелочные функции

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

Видно, что значение this.title не определено, так как this как контекст объекта замещается глобальным контекстом. В этом случае нам надо передать подобное значение this.title или весь контекст объекта.

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

Контекстом для стрелочной функции в данном случае будет выступать контекст объекта school . Соответственно, не надо определять дополнительные переменные для передачи данных в функцию.

4.11. Декомпозиция

Декомпозиция (destructuring) позволяет извлечь из объекта отдельные значения в переменные:

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

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

4.11.1. Декомпозиция массивов

Также можно декомпозировать массивы:

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

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

4.11.2. Декомпозиция параметров

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

4.12. Классы

С внедрением стандарта ES2015 (ES6) в JavaScript появился новый способ определения объектов — с помощью классов. Класс представляет описание объекта, его состояния и поведения, а объект является конкретным воплощением или экземпляром класса.

Для определения класса используется ключевое слово class :

Также можно определить анонимный класс и присвоить его переменной:

После этого можно создать объекты класса с помощью конструктора:

Для создания объекта с помощью конструктора сначала ставится ключевое слово new . Затем собственно идет вызов конструктора — по сути вызов функции по имени класса. По умолчанию классы имеют один конструктор без параметров. Поэтому в данном случае при вызове конструктора в него не передается никаких аргументов.

Также можно определить в классе свои конструкторы. Также класс может содержать свойства и методы:

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

Для хранения состояния в классе определяются свойства. Для их определения используется ключевое слово this . В данном случае в классе два свойства: name и age .

Поведение класса определяют методы. В данном случае определен метод display() , который выводит значения свойств на консоль.

4.12.1. Наследование

Одни классы могут наследоваться от других. Наследование позволяет сократить объем кода в классах-наследниках:

Для наследования одного класса от другого в определении класса применяется оператор extends , после которого идет название базового класса. То есть в данном случае класс Employee наследуется от класса Person . Класс Person еще называется базовым классом, классом-родителем, суперклассом, а класс Employee — классом-наследником, подклассом, производным классом.

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

4.12.2. Статические методы

Статические методы вызываются для всего класса в целом, а не для отдельного объекта. Для их определения применяется оператор static .

5. Встроенные объекты

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

5.1. Объект Date . Работа с датами

Объект Date позволяет работать с датами и временем в JavaScript.

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

В этом случае объект будет указывать на текущую дату компьютера.

Второй способ заключается в передаче в (конструктор) Date количества миллисекунд, которые прошли с начала эпохи Unix, то есть с 1 января 1970 года 00:00:00 GMT:

Третий способ состоит в передаче в конструктор Date дня, месяца и года:

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

Четвертый способ состоит в передаче в конструктор Date всех параметров даты и времени:

При этом надо учитывать, что отсчет месяцев начинается с нуля, то есть январь — 0, а декабрь — 11.

5.1.1. Получение даты и времени

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

getDate() : возвращает день месяца

getDay() : возвращает день недели (отсчет начинается с 0 — воскресенье, и последний день — 6 — суббота)

getMonth() : возвращает номер месяца (отсчет начинается с нуля, то есть месяц с номер 0 — январь)

getFullYear() : возвращает год

toDateString() : возвращает полную дату в виде строки

getHours() : возвращает час (от 0 до 23 )

getMinutes() : возвращает минуты (от 0 до 59 )

getSeconds() : возвращает секунды (от 0 до 59 )

getMilliseconds() : возвращает миллисекунды (от 0 до 999 )

toTimeString() : возвращает полное время в виде строки

5.1.2. Установка даты и времени

Коме задания параметров даты в конструкторе для установки мы также можем использовать дополнительные методы объекта Date :

setDate() : установка дня в дате

setMonth() : уставовка месяца (отсчет начинается с нуля, то есть месяц с номер 0 — январь)

setFullYear() : устанавливает год

setHours() : установка часа

setMinutes() : установка минут

setSeconds() : установка секунд

setMilliseconds() : установка миллисекунд

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

5.2. Объект Math

5.2.1. Математические операции

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

abs() : возвращает абсолютное значение числа.

min() и max() : возвращают соответственно минимальное и максимальное значение из набора чисел.

ceil() : округляет число до следующего наибольшего целого числа.

floor() : округляет число до следующего наименьшего целого числа.

round() : округляет число до следующего наименьшего целого числа, если его десятичная часть меньше 0.5. Если же десятичная часть равна или больше 0.5, то округление идет до ближайшего наибольшего целого числа.

random() : возвращает случайное число с плавающей точкой из диапазона от 0 до 1.

pow() : возвращает число в определенной степени.

sqrt() : возвращает квадратный корень числа.

log() : возвращает натуральный логарифм числа.

5.2.2. Тригонометрические функции

Целый ряд функций представляют тригонометрические функции:

sin() — вычисляет синус угла

cos() — вычисляет косинус угла

tan() — вычисляет тангенс угла

В качестве значения они принимают значение в радианах.

5.2.3. Константы

Кроме методов объект Math также определяет набор встроенных констант, которые можно использовать в различных вычислениях:

Math.PI — число PI: 3.141592653589793

Math.SQRT2 — квадратный корень из двух: 1.4142135623730951

Math.SQRT1_2 — половина от квадратного корня из двух: 0.7071067811865476

Math.E — число e или число Эйлера: 2.718281828459045

Math.LN2 — натуральный логарифм числа 2: 0.6931471805599453

Math.LN10 — натуральный логарифм числа 10: 2.302585092994046

Math.LOG2E — двоичный логарифм числа e: 1.4426950408889634

Math.LOG10E — десятичный логарифм числа e: 0.4342944819032518

5.3. Объект Array . Работа с массивами

Объект Array представляет массив и предоставляет ряд свойств и методов, с помощью которых мы можем управлять массивом.

5.3.1. Инициализация массива

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

Можно сразу же инициализировать массив некоторым количеством элементов:

Можно определить массив и по ходу определять в него новые элементы:

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

5.3.2. length

Чтобы узнать длину массива, используется свойство length :

5.3.3. Копирование массива. slice()

Копирование массива может быть поверхностным или неглубоким (shallow copy) и глубоким (deep copy).

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

Такое поведение не всегда является желательным. Например, необходимо, чтобы после копирования переменные указывали на отдельные массивы. И в этом случае можно использовать глубокое копирование с помощью метода slice() :

Также метод slice() позволяет скопировать часть массива:

5.3.4. push()

Метод push() добавляет элемент в конец массива.

5.3.5. pop()

Метод pop() удаляет последний элемент из массива.

5.3.6. shift()

Метод shift() извлекает и удаляет первый элемент из массива.

5.3.7. unshift()

Метод unshift() добавляет новый элемент в начало массива.

5.3.8. Удаление элемента по индексу. splice()

Метод splice() удаляет элементы с определенного индекса. Например, удаление элементов с третьего индекса:

Метод splice() возвращает удаленные элементы.

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

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

Еще одна версия метода splice() позволяет вставить вместо удаляемых элементов новые элементы:

5.3.9. concat()

Метод concat() служит для объединения массивов:

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

5.3.10. join()

Метод join() объединяет все элементы массива в одну строку:

В метод join() передается разделитель между элементами массива. В данном случае в качестве разделителя будет использоваться запятая , и пробел ` `).

5.3.11. sort()

Метод sort() сортирует массив по возрастанию.

5.3.12. reverse()

Метод reverse() переворачивает массив задом наперед. В сочетании с методом sort() можно отсортировать массив по убыванию.

5.3.13. Поиск индекса элемента
indexOf() и lastIndexOf()

Методы indexOf() и lastIndexOf() возвращают индекс первого и последнего включения элемента в массиве.

every()

Метод every() проверяет, все ли элементы соответствуют определенному условию:

В метод every() в качестве параметра передается функция, представляющая условие.

Параметр value представляет текущий перебираемый элемент массива, параметр index представляет индекс этого элемента, а параметр array передает ссылку на массив.

Метод some() похож на метод every() , только он проверяет, соответствует ли хотя бы один элемент условию. И в этом случае метод some() возвращает true . Если элементов, соответствующих условию, в массиве нет, то возвращается значение false .

filter()

Метод filter() , как some() и every() , принимает функцию условия. Но при этом возвращает массив* тех элементов, которые соответствуют этому условию.

forEach() и map()

Методы forEach() и map() осуществляют перебор элементов и выполняют с ними определенный операции. Например, для вычисления квадратов чисел в массиве можно использовать следующий код:

Но с помощью метода forEach() можно упростить эту конструкцию:

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

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

5.4. Объект Number

Объект Number представляет числа. Чтобы создать число, надо передать в конструктор Number число или стоку, представляющую число:

Однако создавать объект Number можно и просто присвоив переменной определенное число:

Объект Number предоставляет ряд свойств и методов. Некоторые его свойства:

Number.MAX_VALUE : наибольшее возможное число. Приблизительно равно 1.79E+308. Числа, которые больше этого значения, рассматриваются как Infinity

Number.MIN_VALUE : наименьшее возможное положительное число. Приблизительно равно 5e-324 (где-то около нуля)

Number.NaN : специальное значение, которое указывает, что объект не является числом

Number.NEGATIVE_INFINITY : значение, которое обозначает отрицательную неопределенность и которое возникает при переполнении. Например, если складывать два отрицательных числа, которые по модулю равны Number.MAX_VALUE

Number.POSITIVE_INFINITY : положительная неопределенность. Также, как и отрицательная неопределенность, возникает при переполнении, только теперь в положительную сторону

parseFloat() : преобразует строку в число с плавающей точкой.

parseInt(): преобразует строку в целое число.

toFixed() : оставляет в числе с плавающей точкой определенное количество знаков в дробной части.

isNaN() : определяет, является ли объект числом. Если объект не является числом, то возвращается значение true .

Но следующее выражение вернет false , хотя значение не является числом:

Чтобы избежать подобных ситуаций, лучше применять глобальную функцию isNaN() :

6. Строки

6.1. Строки и объект String

Для создания строк можно как напрямую присваивать переменной строку:

Для работы со строками предназначен объект String , поэтому также можно использовать конструктор String :

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

Объект String имеет большой набор свойств и методов, с помощью которых мы можем манипулировать строками.

Свойство length указывает на длину строки:

6.1.1. Шаблоны строк

Шаблоны строк позволяют вставлять в строку различные значения. Для этого строки заключаются в косые кавычки ` :

Для вставки значения в строку оно заключается в фигурные скобки, перед которыми ставится знак доллара $ .

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

6.1.2. Поиск в строке

Для поиска в строке некоторой подстроки используются методы indexOf() (индекс первого вхождения подстроки) и lastIndexOf() (индекс последнего вхождения подстроки*. Эти методы принимают два параметра:

Подстроку, которую надо найти

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

Оба метода возвращают индекс символа, с которого в строке*начинается подстрока. Если подстрока не найдена, то возвращается число -1 .

Еще один метод — includes() возвращает true , если строка содержит определенную подстроку. С помощью второго дополнительного параметра можно определить индекс, с которого будет начинаться поиск подстроки.

6.1.3. Выбор подстроки

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

Метод substring() принимает два параметра:

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

индекс, до которого надо обрезать строку

Метод substr() также в качестве первого параметра принимает начальный индекс подстроки, а в качестве второго — длину вырезаемой подстроки. Если второй параметр не указывается, то обрезается вся остальная часть строки.

6.1.4. Управление регистром

Для изменения регистра имеются методы toLowerCase() (для перевода в нижний регистр) и toUpperCase() (для перевода в верхний регистр).

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

Чтобы получить определенный символ в строке по индексу, можно применять методы charAt() и charCodeAt() . Оба метода в качестве параметра принимают индекс символа.

Но если в качестве результата метод charAt() возвращает сам символ, то метод charCodeAt() возвращает числовой код этого символа.

6.1.6. Удаление пробелов

Для удаления начальных и концевых пробелов в стоке используется метод trim() .

6.1.7. Объединение строк

Метод concat() объединяет две строки.

6.1.8. Замена подстроки

Метод replace() заменяет первое вхождение одной подстроки на другую.

6.1.9. Разделение строки

Метод split() разбивает строку на массив подстрок по определенному разделителю. В качестве разделителя используется строка, которая передается в метод.

6.1.10. Проверка начала и окончания строки

Метод startsWith() возвращает true , если строка начинается с определенной подстроки. А метод endsWith() возвращает true , если строка оканчивается на определенную подстроку. При этом играет роль регистр символов.

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

6.2. Объект RegExp

6.2.1. Регулярные выражения

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

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

6.2.2. Методы RegExp

Чтобы определить, соответствует ли регулярное выражение строке, в объекте RegExp определен метод test() . Этот метод возвращает true , если строка соответствует регулярному выражению, и false , если не соответствует.

Аналогично работает метод exec() — он также проверяет, соответствует ли строка регулярному выражению, только теперь данный метод возвращает ту часть строки, которая соответствует выражению. Если соответствий нет, то возвращается значение null .

6.2.3. Группы символов

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

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

Если, наоборот, не надо, чтобы строка имела только определенные символы, то необходимо в квадратных скобках перед перечислением символов ставить знак ^ :

6.2.4. Свойства выражений

Свойство global позволяет найти все подстроки, которые соответствуют регулярному выражению. По умолчанию при поиске подстрок регулярное выражение выбирает первую попавшуюся подстроку из строки, которая соответствует выражению. Хотя в строке может быть множество подстрок, которые также соответствуют выражению. Для этого применяется данное свойство в виде символа g в выражениях

Свойство ignoreCase позволяет найти подстроки, которые соответствуют регулярному выражению, вне зависимости от регистра символов в строке. Для этого в регулярных выражениях применяется символ i

Свойство multiline позволяет найти подстроки, которые соответствуют регулярному выражению, в многострочном тексте. Для этого в регулярных выражениях применяется символ m

6.3. Регулярные выражения в методах String

Ряд методов объекта String могут использовать регулярные выражения в качестве параметра.

6.3.1. Разделение строки. Метод split()

Метод split() может использовать регулярные выражения для разделения строк:

6.3.2. Метод match()

Для поиска всех соответствий в строке применяется метод match() :

6.3.3. Поиск в строке. Метод search()

Метод search() находит индекс первого включения соответствия в строке:

6.3.4. Замена. Метод replace()

Метод replace() позволяет заменить все соответствия регулярному выражению определенной строкой:

7. Работа с браузером и BOM

7.1. Browser Object Model и объект window

Большое значение в JavaScript имеет работа с web-браузером и теми объектами, которые он предоставляет. Например, использование объектов браузера позволяет манипулировать элементами html, которые имеются на странице, или взаимодействовать с пользователем.

Все объекты, через которые JavaScript взаимодействует с браузером, описываются таким понятием как Browser Object Model (Объектная Модель Браузера).

Browser Object Model можно представить в виде следующей схемы:

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

7.1.1. Объект window

Объект window представляет собой окно web-браузера, в котором размещаются web-страницы. window является глобальным объектом, поэтому при доступе к его свойствам и методам необязательно использовать его имя. Например, window имеет метод alert() , который отображает окно сообщения. Но нам необязательно писать:

window можно не использовать:

Но так как данный объект глобальный, то это накладывает некоторые ограничения. Например:

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

И если мы объявим в программе какую-нибудь глобальную переменную, то она нам доступна как свойство в объекте window :

7.2. Управление окнами

7.2.1. Диалоговые окна

Для взаимодействия с пользователем в объекте window определен ряд методов, которые позволяют создавать диалоговые окна.

Метод alert()

Метод alert() выводит окно с сообщением:

Метод confirm()

Метод confirm() отображает окно с сообщением, в котором пользователь должен подтвердить действие двух кнопок OK и Отмена. В зависимости от выбора пользователя метод возвращает:

true если пользователь нажал OK

false если пользователь нажал кнопку Отмены

Функция confirm в JavaScript

Метод prompt()

Метод prompt() позволяет с помощью диалогового окна запрашивать у пользователя какие-либо данные. Данный метод возвращает введенное пользователем значение:

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

Функция prompt в JavaScript

7.2.2. Открытие, закрытие и позиционирование окон

Объект window также предоставляет ряд методов для управления окнами браузера.

Метод open()

Метод open() открывает определенный ресурс в новом окне браузера:

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

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

width : ширина окна в пикселях. Например, width=640

height : высота окна в пикселях. Например, height=480

left : координата x относительно начала экрана в пикселях. Например, left=0

top : координата y относительно начала экрана в пикселях. Например, top=0

titlebar : будет ли окно иметь строку с заголовком. Например, titlebar=no

menubar : будет ли окно иметь панель меню. Например, menubar=yes

toolbar : будет ли окно иметь панели инструментов. Например, toolbar=yes

location : будет ли окно иметь адресную строку. Например, location=no

scrollbars : допускается ли наличие полос прокрутки. Например, scrollbars=yes

status : наличие статусной строки. Например, status=yes

resizable : может ли окно изменять размеры. Например, resizable=no

Метод close()

С помощью метода close() можно закрыть окно. Например, откроем новое окно и через 10 секунд закроем его:

Метод moveTo()

Метод moveTo() позволяет переместить окно на новую позицию:

В данном случае окно перемещается на позицию с координатами x равные 50 , y равные 50 относительно левого верхнего угла экрана.

Метод resizeTo()

Метод resizeTo() позволяет изменить размеры окна:

7.3. История браузера

Объект history предназначен для хранения истории посещений web-страниц в браузере. Этот объект доступен через объект window .

Все сведения о посещении пользователя хранятся в специальном стеке (history stack). С помощью свойства length можно узнать, как много web-станиц хранится в стеке:

Для перемещения по страницам в истории в объекте history определены методы:

back() : перемещение к прошлой посмотренной странице

forward() : перемещение к следующей просмотренной странице

Также в объекте history определен специальный метод go() , который позволяет перемещаться вперед и назад по истории на определенное число страниц. Например, переместимся на 2 страницы назад:

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

7.4. Расположение web-страницы

Объект location содержит информацию о расположении текущей web-страницы: URL, информацию о сервере, номер порта, протокол. С помощью свойств объекта мы можем получить эту информацию:

href : полная строка запроса к ресурсу

pathname : путь к ресурсу

origin : общая схема запроса

port : порт, используемый ресурсом

hostname : название хоста

hash : если строка запроса содержит символ решетки ( # ), то данное свойство возвращает ту часть строки, которая идет после этого символа

search : если строка запроса содержит знак вопроса ( ? ), например, то данное свойство возвращает ту часть строки, которая идет после знака вопроса

Например, пусть есть следующая web-страница test.html , которая лежит на локальном web-сервере:

Объект location в JavaScript

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

assign(url) : загружает ресурс, который находится по пути url

reload(forcedReload) : перезагружает текущую web-страницу. Параметр forcedReload указывает, надо ли использовать кэш браузера. Если параметр равен true , то кэш не используется

replace(url) : заменяет текущую web-станицу другим ресурсом, который находится по пути url . В отличие от метода assign , который также загружает web-станицу с другого ресурса, метод replace не сохраняет предыдущую web-страницу в стеке истории переходов history , поэтому мы не сможем вызвать метод history.back() для перехода к ней.

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

Переход на другой локальный ресурс:

7.5. Информация о браузере и операционной системе

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

Данное свойство хранит полную стоку юзер-агента, например, Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:89.0) Gecko/20100101 Firefox/89.0

Чтобы вычленить из этой информации непосредственно браузер, можно попробовать найти в этой информации название браузера:

7.5.1. Географическое положение пользователя

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

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

latitude : географическая широта

longitude : географическая долгота

speed : скорость, с которой перемещается пользователь (например, если он идет или перемещается на транспорте)

При этом надо учитывать, что в браузерах действует политика безопасности, которая при обращении к методу geolocation.getCurrentPosition() отображает пользователю сообщение, в котором пользователь может подтвердить отправку географических координат. Если же пользователь откажется, то будет срабатывать функция error() .

Объект geolocation в JavaScript

7.6. Таймеры

Для выполнения действий через определенные промежутки времени в объекте window предусмотрены функции таймеров. Есть два типа таймеров:

срабатывающие только один раз

срабатывающие постоянно через промежуток времени

7.6.1. Функция setTimeout()

Для одноразового выполнения действий через промежуток времени предназначена функция setTimeout() . Она может принимать два параметра:

Параметр period указывает на промежуток, через который будет выполняться функция из параметра someFunction . А в качестве результата функция возвращает id таймера.

В данном случае через 3 секунды после загрузки страницы произойдет срабатывание функции timerFunction .

Для остановки таймера применяется функция clearTimeout() .

7.6.2. Функция setInterval()

Функции setInterval() и clearInterval() работают аналогично функциям setTimeout() и clearTimeout() с той лишь разницей, что setInterval() постоянно выполняет определенную функцию через промежуток времени.

Например, напишем небольшую программу для вывода текущего времени:

Здесь через каждую секунду ( 1000 миллисекунд) вызывается функция updateTime() , которая обновляет содержимое элемента <div > , устанавливая в качестве его значения текущее время.

7.6.3. Функция requestAnimationFrame()

Метод requestAnimationFrame() действует аналогично setInterval() за тем исключением, что он больше заточен под анимацию, работу с графикой и имеет ряд оптимизаций, которые улучшают его производительность.

В метод window.requestAnimationFrame() передается функция, которая будет вызываться определенное количество раз в секунду (обычно 60 кадров в секунду или же FPS). В данном случае в этот метод передается функция rotate , которая изменяет угол поворота блока на странице и затем обращается опять же к методу window.requestAnimationFrame(rotate) .

В качестве возвращаемого результата метод window.requestAnimationFrame() возвращает уникальный id , который может потом использоваться для остановки анимации:

8. Работа с DOM

Одой из ключевых задач JavaScript является взаимодействие с пользователем и манипуляция элементами web-страницы. Для JavaScript web-страница доступна в виде объектной модели документа (document object model) или сокращенно DOM. DOM описывает структуру web-страницы в виде древовидного представления и предоставляет разработчикам способ получить доступ к отдельным элементам web-страницы.

Важно не путать понятия BOM (Browser Object Modelобъектная модель браузера) и DOM (объектная модель документа). Если BOM предоставляет доступ к браузеру и его свойствам в целом, то DOM предоставляет доступ к отдельной web-странице или HTML-документу и его элементам.

Рассмотрим простейшую web-страницу:

Дерево DOM для этой страницы будет выглядеть следующим образом:

дерево HTML страницы

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

Существует следующие виды узлов:

Element: HTML-элемент

Attr: атрибут HTML-элемента

Document: корневой узел HTML-документа

DocumentType: DTD или тип схемы XML-документа

DocumentFragment: место для временного хранения частей документа

EntityReference: ссылка на сущность XML-документа

ProcessingInstruction: инструкция обработки web-страницы

Comment: элемент комментария

Text: текст элемента

CDATASection: секция CDATA в документе XML

Entity: необработанная сущность DTD

Notation: нотация, объявленная в DTD

8.1. Объект document

Для работы со структурой DOM в JavaScript предназначен объект document , который определен в глобальном объекте window . Объект document предоставляет ряд свойств и методов для управления элементами страницы.

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

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

getElementById(value) : выбирает элемент, у которого атрибут id равен value

getElementsByTagName(value) : выбирает все элементы, у которых тег равен value

getElementsByClassName(value) : выбирает все элементы, которые имеют класс value

querySelector(value) : выбирает первый элемент, который соответствует css-селектору value

querySelectorAll(value) : выбирает все элементы, которые соответствуют css-селектору value

Например, найдем элемент по id :

С помощью вызова document.getElementById(«header») находим элемент, у которого id=»header» . А с помощью свойства innerText можно получить текст найденного элемента.

Поиск по определенному тегу:

С помощью вызова document.getElementsByTagName(«p») находим все элементы параграфов. Этот вызов возвращает массив найденных элементов. Поэтому, чтобы получить отдельные элементы массива, необходимо пробежаться по ним в цикле.

Если нам надо получить только первый элемент, то можно к первому элементу найденной коллекции объектов:

Получение элемента по классу:

Выбор по селектору CSS:

Выражение document.querySelector(«.annotation p») находит элемент, который соответствует селектору .annotation p . Если на странице несколько элементов, соответствующих селектору, то метод выберет первый из них. В итоге браузер выведет:

Чтобы получить все элементы по селектору, можно подобным образом использовать метод document.querySelectorAll() , который возвращает массив найденных элементов:

8.2. Свойства объекта document

Кроме ранее рассмотренных методов объект document позволяет обратиться к определенным элементам web-страницы через свойства:

documentElement : предоставляет доступ к корневому элементу <html>

body : предоставляет доступ к элементу <body> на web-странице

images : содержит коллекцию всех объектов изображений (элементов img )

links : содержит коллекцию ссылок — элементов <a> и <area> , у которых определен атрибут href

anchors : предоставляет доступ к коллекции элементов <a> , у которых определен атрибут name

forms : содержит коллекцию всех форм на web-странице

Эти свойства не предоставляют доступ ко всем элементам, однако позволяют получить наиболее часто используемые элементы на web-странице.

Получение всех изображений на странице:

Подобно тому, как в коде HTML можно установить атрибуты у элемента img , так и в коде JavaScript можно через свойства src и alt получить и установить значения этих атрибутов.

Рассмотрим получение всех ссылок на странице:

Подобно тому, как в коде HTML можно установить атрибуты у элемента img , так и в коде javascript можно через свойства src и alt получить и установить значения этих атрибутов.

8.3. Объект Node

Каждый отдельный узел, будь то HTML-элемент, его атрибут или текст, в структуре DOM представлен объектом Node . Этот объект предоставляет ряд свойств, с помощью которых мы можем получить информацию о данном узле:

childNodes : содержит коллекцию дочерних узлов

firstChild : возвращает первый дочерний узел текущего узла

lastChild : возвращает последний дочерний узел текущего узла

previousSibling : возвращает предыдущий элемент, который находится на одном уровне с текущим

nextSibling : возвращает следующий элемент, который находится на одном уровне с текущим

ownerDocument : возвращает корневой узел документа

parentNode : возвращает элемент, который содержит текущий узел

nodeName : возвращает имя узла

nodeType : возвращает тип узла в виде числа. 1 — элемент, 2 — атрибут, 3 — текст

nodeValue : возвращает или устанавливает значение узла в виде простого текста

8.4. Создание, добавление элементов web-страницы

Для создания элементов объект document имеет следующие методы:

createElement(elementName) : создает HTML-элемент, тег которого передается в качестве параметра. Возвращает созданный элемент

createTextNode(text) : создает и возвращает текстовый узел. В качестве параметра передается текст узла.

Переменная elem будет хранить ссылку на элемент div . Однако одного создания элементов недостаточно, их еще надо добавить на web-страницу.

Для добавления элементов мы можем использовать один из методов объекта Node :

appendChild(newNode) : добавляет новый узел newNode в конец коллекции дочерних узлов

insertBefore(newNode, referenceNode) : добавляет новый узел newNode перед узлом referenceNode

Однако необязательно для определения текста внутри элемента создавать дополнительный текстовый узел, так как мы можем воспользоваться свойством textContent и напрямую ему присвоить текст:

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

8.4.1. Копирование элементов

Иногда элементы бывают довольно сложными по составу, и гораздо проще их скопировать, чем с помощью отдельных вызовов создавать из содержимое. Для копирования уже имеющихся узлов у объекта Node можно использовать метод cloneNode() .

В метод cloneNode() в качестве параметра передается логическое значение: если передается true , то элемент будет копироваться со всеми дочерними узлами; если передается false — то копируется без дочерних узлов.

8.4.2. Удаление элемента

Для удаления элемента вызывается метод removeChild(removalNode) объекта Node . Этот метод удаляет один из дочерних узлов.

8.4.3. Замена элемента

Для замены элемента применяется метод replaceChild(newNode, oldNode) объекта Node .

8.5. Объект Element

Кроме методов и свойств объекта Node в JavaScript мы можем использовать свойства и методы объектов Element . Важно не путать эти два объекта: Node и Element . Node представляет все узлы web-страницы, в то время как объект Element представляет непосредственно только HTML-элементы. То есть объекты Element — это фактически те же самые узлы — объекты Node , у которых тип узла (свойство nodeType ) равно 1.

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

8.5.1. Свойства innerText и innerHTML

Для получения или установки текстового содержимого элемента можно использовать свойство innerText , а для получения или установки HTML-кода — свойство innerHTML .

Надо отметить, что свойство innerText во многом аналогично свойству textContent . То есть следующие вызовы будут равноценны:

Установка HTML-кода у элемента:

8.5.2. Методы объекта Element

Среди методов объекта Element можно отметить методы управления атрибутами:

getAttribute(attr) : возвращает значение атрибута attr

setAttribute(attr, value) : устанавливает для атрибута attr значение value . Если атрибута нет, то он добавляется

removeAttribute(attr) : удаляет атрибут attr и его значение

Работа с атрибутами:

8.5.3. Размеры и позиция элементов

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

Свойства offsetWidth и offsetHeight определяют соответственно ширину и высоту элемента в пикселях. В ширину и высоту включается граница элемента.

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

Для определения позиции элемента наиболее эффективным способом является метод getBoundingClientRect() .

Этот метод возвращает объект со свойствами top , bottom , left , right , которые указывают на смещение элемента относительно верхнего левого угла браузера.

8.5.4. Изменение стиля элементов

Для работы со стилевыми свойствами элементов в JavaScript применяются, главным образом, два подхода:

Изменение свойства style

Изменение значения атрибута class

Свойство style

Свойство style представляет сложный объект для управления стилем и напрямую сопоставляется с атрибутом style HTML-элемента. Этот объект содержит набор свойств CSS: element.style.свойствоCSS .

Однако ряд свойств CSS в названиях имеют дефис, например, font-family . В JavaScript для этих свойств дефис не употребляется. Только первая буква, которая идет после дефиса, переводится в верхний регистр.

Свойство className

С помощью свойства className можно установить атрибут class HTML-элемента:

Благодаря использованию классов не придется настраивать каждое отдельное свойство css с помощью свойства style .

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

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

Свойство classList

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

add(className) : добавляет класс className

remove(className) : удаляет класс className

toggle(className) : переключает у элемента класс на className . Если класса нет, то он добавляется, если есть, то удаляется

8.6. Создание своего элемента HTML

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

В JavaScript HTML-элемент представлен интерфейсом HTMLElement . Соответственно, реализуя данный интерфейс в JavaScript, мы можем создать свои классы, которые будут представлять HTML-элементы, и потом их использовать.

Чтобы определить класс, который будет представлять HTML-элемент, достаточно создать класс, который реализует интерфейс HTMLElement :

Второй важный момент — нужно зарегистрировать разработанный HTML-элемент, что бы браузер знал, что есть такой элемент. Для этого применяется встроенная функция:

Она принимает три параметра:

name : имя разработанного элемента HTML, который будет представлять класс JavaScript. Важно: имя должно содержать дефис.

constructor : конструктор (по сути класс JavaScript), который представляет разработанный элемент HTML.

options : необязательный параметр — объект, который настраивает разработанный HTML-элемент.

Как правило, классы кастомных элементов применяют конструктор. Причем в самом начале конструктора должен идти вызов функции super() , который гарантирует, что класс унаследовал все методы, атрибуты и свойства интерфейса HTMlElement .

Но кроме того, в конструкторе мно определить некоторую базовую логику элемента.

8.6.1. Добавление методов

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

8.6.2. События жизненного цикла

Кастомный элемент HTML имеет свой жизненный цикл, который описывается следующими методами:

connectedCallback : вызывается каждый раз, когда разработанный HTML-элемент добавляется в DOM.

disconnectedCallback : вызывается каждый раз, когда разработанный HTML-элемент удаляется из DOM.

adoptedCallback : вызывается каждый раз, когда разработанный HTML-элемент перемещается в новый элемент.

attributeChangedCallback : вызывается при каждом изменении (добавлении, изменении значения или удаления) атрибута разработанного HTML-элемента.

8.6.3. Добавление атрибутов

Также мы можем определить у элемента свои атрибуты и затем использовать их.

8.6.4. Стилизация CSS

Стилизация элемента через CSS производится так же, как и стилизация любого другого элемента.

9. События

9.1. Введение в обработку событий

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

В JavaScript есть следующие типы событий:

События мыши (перемещение курсора, нажатие мыши и т.д.)

События клавиатуры (нажатие или отпускание клавиши клавиатуры)

События жизненного цикла элементов (например, событие загрузки web-страницы)

События элементов форм (нажатие кнопки на форме, выбор элемента в выпадающем списке и т.д.)

События, возникающие при изменении элементов DOM

События, возникающие при касании на сенсорных экранах

События, возникающие при возникновении ошибок

Рассмотрим простейшую обработку событий. Например, на web-странице у нас есть следующий элемент div :

Здесь определен обычный блок div , который имеет атрибут onclick задающий обработчик события _нажатия на блок div . То есть, чтобы обработать какое-либо событие, нам надо определить для него обработчик. Обработчик представляет собой код на языке JavaScript. В данном случае обработчик выглядит довольно просто:

И при нажатии на кнопку будет появляться всплывающее окно:

Пример события

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

Теперь обработчиком события будет выступать функция displayMessage() .

9.1.1. Передача параметров обработчику события

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

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

Кроме того, надо отметить, что здесь обработчик возвращает результат. Хотя в первом примере с блоком div от обработчика не требовалось возвращения результата. Дело в том, что для некоторых обработчиков можно подтвердить или остановить обработку события. Например, нажатие на ссылку должно привести к переадресации. Но возвращая из обработчика false , можно остановить стандартный путь обработки события, и переадресации не будет. Если же возвращать значение true , то событие обрабатывается в стандартном порядке.

Если же убрать возвращение результата, то событие будет обрабатываться, как будто возвращается значение true :

Кроме непосредственно элемента-источника события, обработчику можно передавать объект event . Этот объект не определяется разработчиком, это просто аргумент функции обработчика, который хранит всю информацию о событии. Например:

В данном случае с помощью свойства type объекта event получаем тип события (в данном случае тип click ).

9.2. Обработчики событий

9.2.1. Встроенные обработчики

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

Хотя этот подход прекрасно работает, но он имеет кучу недостатков:

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

Обработчики событий можно задать только для уже созданных на web-странице элементов. Динамически создаваемые элементы в этом случае лишаются возможности обработки событий.

К элементу для одного события может быть прикреплен только один обработчик.

Нельзя удалить обработчик без изменения кода

9.2.2. Свойства обработчиков событий

Проблемы, которые возникают при использовании встроенных обработчиков, были призваны решить свойства обработчиков. Подобно тому, как у HTML-элементов есть атрибуты для обработчиков, так и в коде JavaScript у элементов DOM можно получить свойства обработчиков, которые соответствуют атрибутам:

В итоге достаточно взять свойство onclick и присвоить ему функцию, используемую в качестве обработчика. За счет этого код HTML отделяется от кода JavaScript.

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

9.2.3. Слушатели событий

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

Для работы со слушателями событий в JavaScript есть объект EventTarget , который определяет методы

addEventListener() для добавления слушателя

removeEventListener() для удаления слушателя

Поскольку HTML-элементы DOM тоже являются объектами EventTarget , то они также имеют эти методы. Фактически слушатели представляют те же функции обработчиков.

Метод addEventListener() принимает два параметра: название события без префикса on и функцию обработчика этого события.

То есть в данном случае опять же обрабатывается событие click . И также можно было бы в качестве второго параметра название функции:

Удаление слушателя аналогично добавлению:

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

9.3. Объект Event

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

bubbles : возвращает true , если событие является восходящим. Например, если событие возникло на вложенном элементе, то оно может быть обработано на родительском элементе.

cancelable : возвращает true , если можно отменить стандартную обработку события.

currentTarget : определяет элемент, к которому прикреплен обработчик события.

defaultPrevented : возвращает true , если был вызван у объекта Event метод preventDefault() .

eventPhase : определяет стадию обработки события.

target : указывает на элемент, на котором было вызвано событие.

timeStamp : хранит время возникновения события.

type : указывает на имя события.

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

9.3.1. Остановка выполнения события

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

Например, запретим переход по ссылке после 12 часов:

9.4. Распространение событий

Когда нажимают на какой-либо элемент на станице и генерируется событие нажатия, то это событие может распространяться от элемента к элементу. Например, если нажать на блок div , то также нажимаем и на элемент body , в котором блок div находится. То есть происходит распространение события.

Есть две форм распространения событий:

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

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

9.4.1. Восходящие события

Рассмотрим восходящие события, которые распространяются в верх по дереву DOM. Допустим, у нас есть следующая web-страница:

Если нажать на вложенный div , то событие пойдет к родительскому элементу div и далее к элементу body :

Восходящее событие

Надо сказать, что подобное поведение не всегда является желательным. И в этом случае можно остановить распространение событие с помощью метода stopPropagation() объекта Event :

И в результате нажатия событие будет обработано только обработчиком для redRect .

9.4.2. Нисходящие события

События также могут быть нисходящими. Для их использования в метод addEventListener() в качестве третьего необязательного параметра передается логическое значение true или false , которое указывает, будет ли событие нисходящим. По умолчанию все события восходящие.

Возьмем ту же web-станицу, только изменим ее код JavaScript:

Теперь события будут распространяться в обратном порядке:

Восходящее событие в обратном порядке

9.5. События мыши

Одну из наиболее часто используемых событий составляют события мыши:

click : возникает при нажатии указателем мыши на элемент

mousedown : возникает при нахождении указателя мыши на элементе, когда кнопка мыши находится в нажатом состоянии

mouseup : возникает при нахождении указателя мыши на элементе во время отпускания кнопки мыши

mouseover : возникает при вхождении указателя мыши в границы элемента

mousemove : возникает при прохождении указателя мыши над элементом

mouseout : возникает, когда указатель мыши выходит за пределы элемента

Например, обработаем события mouseover и mouseout :

Теперь при наведении указателя мыши на блок blueRect он будет окрашиваться в красный цвет, а при уходе указателя мыши — блок будет обратно окрашиваться в синий цвет.

Объект Event является общим для всех событий. Однако для разных типов событий существуют также свои объекты событий, которые добавляют ряд своих свойств. Так, для работы с событиями указателя мыши определен объект MouseEvent , который добавляет следующие свойства:

altKey : возвращает true , если была нажата клавиша Alt во время генерации события.

button : указывает, какая кнопка мыши была нажата.

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

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

ctrlKey : возвращает true , если была нажата клавиша Ctrl во время генерации события.

metaKey : возвращает true , если была нажата во время генерации события метаклавиша клавиатуры.

relatedTarget : определяет вторичный источник возникновения события.

screenX : определяет координату Х относительно верхнего левого угла экрана монитора, на которой находился указатель мыши во время генерации события.

screenY : определяет координату Y относительно верхнего левого угла экрана монитора, на которой находился указатель мыши во время генерации события.

shiftKey : возвращает true , если была нажата клавиша Shift во время генерации события.

Определим координаты клика:

9.6. События клавиатуры

Другим распространенным типом событий являются события клавиатуры.

keydown : возникает при нажатии клавиши клавиатуры и длится, пока нажата клавиша.

keyup : возникает при отпускании клавиши клавиатуры.

keypress : возникает при нажатии клавиши клавиатуры, но после события keydown и до события keyup . Надо учитывать, что данное событие генерируется только для тех клавиш, которые формируют вывод в виде символов, например, при печати символов. Нажатия на остальные клавиши, например, на Alt, не учитываются.

Для работы с событиями клавиатуры определен объект KeyboardEvent , который добавляет к свойствам объекта Event ряд специфичных для клавиатуры свойств:

altKey : возвращает true , если была нажата клавиша Alt во время генерации события.

key : возвращает символ нажатой клавиши, например, при нажатии на клавишу T это свойство будет содержать T . А если нажата клавиша Я, то это свойство будет содержать Я .

code : возвращает строковое представление нажатой клавиши физической клавиатуры QWERTY, например, при нажатии на клавишу T это свойство будет содержать KeyT , а при нажатии на клавишу ; (точка запятой), то свойство возвратит Semicolon .

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

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

ctrlKey : возвращает true , если была нажата клавиша Ctrl во время генерации события.

metaKey : возвращает true , если была нажата во время генерации события метаклавиша клавиатуры.

shiftKey : возвращает true , если была нажата клавиша Shift во время генерации события.

Например, можно с помощью клавиш клавиатуры перемещать элемент на web-странице:

В данном случае обрабатывается событие keydown . В обработчике moveRect с помощью метода window.getComputedStyle() получаем стиль элемента blueRect . А затем из этого стиля выбираем значения свойств marginLeft и marginTop .

С помощью свойства e.key получаем нажатую клавишу. Список кодов клавиш клавиатуры можно посмотреть на странице https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values.

Здесь нас интересуют четыре клавиши: вверх, вниз, влево, вправо. Им соответственно будут соответствовать названия ArrowTop , ArrowDown , ArrowLeft и ArrowRight . Если одна из них нажата, производим действия: увеличение или уменьшение отступа элемента от верхней или левой границы. Ну и чтобы элемент не выходил за границы окна, проверяем предельные значения с помощью document.documentElement.clientWidth (ширина корневого элемента) и document.documentElement.clientHeight .

10. Работа с формами

10.1. Формы и их элементы

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

Для создания формы используется элемент <form> :

В JavaScript форма представлена объектом HtmlFormElement . И после создания формы можно к ней обратиться различными способами.

Первый способ заключается в прямом обращении по имени формы:

Второй способ состоит в обращении к коллекции форм документа и поиске в ней нужной формы:

С помощью свойства name объекта формы можно получить значение атрибута name у соответствующего элемента формы в коде HTML.

Еще один способ сочетает оба подхода:

И также можно применять стандартные способы для поиска элемента формы, например, по идентификатору, по тегу или по селектору.

Форма имеет ряд свойств, из которых наиболее важными являются, рассмотренное выше, свойство name . Так же имеется свойство elements , которое содержит коллекцию элементов формы.

Пример формы

Среди методов формы надо отметить метод submit() , который отправляет данные формы на сервер. Так же есть метод reset() , который очищает поля формы.

10.1.1. Элементы форм

Форма может содержать различные элементы ввода HTML: input , textarea , button , select и т.д. Но все они имеют ряд общих свойств и методов.

Так же, как и форма, элементы форм имеют свойство name , с помощью которого можно получить значение атрибута name :

Другим важным свойством является свойство value , которое позволяет получить или изменить значение поля:

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

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

Свойство type позволяет получить тип поля ввода. Это либо название тега элемента, либо значение атрибута type у элементов input .

Из методов можно выделить методы:

focus() : устанавливает фокус на элемент

blur() : убирает фокус с элемента

10.2. Кнопки

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

Либо элемент input :

С точки зрения функциональности в HTML эти элементы не совсем равноценны, но в данном случае они нас интересуют с точки зрения взаимодействия с кодом JavaScript.

При нажатии на любой из этих двух вариантов кнопки происходит отправка формы по адресу, который указан у формы в атрибуте action , либо по адресу web-страницы, если атрибут action не указан. Однако в коде JavaScript можно перехватить отправку, обрабатывая событие click .

При нажатии на кнопку происходит событие click , и для его обработки к кнопке прикрепляем обработчик sendForm . В этом обработчике проверяем введенный в текстовое поле текст. Если его длина больше 5 символов, то выводим сообщение о недопустимой длине и прерываем обычный ход события с помощью вызова e.preventDefault() . В итоге форма не отправляется.

Если же длина текста меньше шести символов, то также выводится сообщение, и затем форма отправляется.

Также можно при необходимости при отправке изменить адрес, на который отправляются данные:

В данном случае, если длина текста больше 5 символов, то текст отправляется, только теперь он отправляется по адресу PostForm , поскольку задано свойство action :

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

При нажатии на кнопки произойдет очистка форм. Но также функциональность по очистке полей формы можно реализовать с помощью метода reset() :

Кроме специальных кнопок отправки и очистки на форме также может использоваться обычная кнопка:

При нажатии на подобную кнопку отправки данных не происходит, хотя также генерируется событие click :

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

Пример параграфа

10.3. Текстовые поля

Для ввода простейшей текстовой информации предназначены элементы <input type=»text» :

Данный элемент поддерживает ряд событий, в частности:

focus : происходит при получении фокуса.

blur : происходит при потере фокуса.

change : происходит при изменении значения поля.

select : происходит при выделении текста в текстовом поле.

keydown : происходит при нажатии клавиши клавиатуры.

keypress : происходит при нажатии клавиши клавиатуры для печатаемых символов.

keyup : происходит при отпускании ранее нажатой клавиши клавиатуры.

Здесь к текстовому полю прикрепляется три обработчика для событий blur , focus и change . Обработка события change позволяет сформировать что-то вроде привязки: при изменении текста весь текст отображается в блоке printBlock . Но надо учитывать, что событие change возникает не сразу после изменения текста, а после потери им фокуса.

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

Поле ввода

Кроме данного текстового поля есть еще специальные поля ввода. Так, поле <input type=»password» предназначено для ввода пароля. По функциональности оно во многом аналогично обычному текстовому полю за тем исключением, что для вводимых символов используется маска:

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

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

10.3.1. Элемент textarea

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

Данные элемент генерирует все те же самые события, что и обычное текстовое поле:

Здесь к текстовому полю прикрепляются обработчики для событий keypress и keydown . В обработчике keypress получаем введенный символ с помощью конвертации числового кода клавиши в строку:

Затем символ добавляется к содержимому блока printBlock .

Событие keypress возникает при нажатии на клавиши для печатаемых символов, то такие символы отображаются в текстовом поле. Однако есть и другие клавиши, которые оказывают влияние на текстовое поле, но они не дают отображаемого символа, поэтому не отслеживаются событием keypress . К таким клавишам относится клавиша Backspace, которая удаляет последний символ. И для ее отслеживания также обрабатываем событие keydown . В обработчике keydown удаляем из строки в блоке printBlock последний символ.

Блок для ввода

10.4. Флажки и переключатели

Особую группу элементов ввода составляют флажки и переключатели.

10.4.1. Флажки

Флажки представляют поле, создаваемое с помощью элемента <input type=»checkbox» и в которое можно поставить отметки. Отличительную особенность флажка составляет свойство checked , которое в отмеченном состоянии принимает значение true :

Нажатие на флажок генерирует событие click . В данном случае при обработке данного события просто выводится информация, отмечен ли данный флажок, в блок div .

Флажок

10.4.2. Переключатели

Переключатели представляют группы кнопок, из которых можно выбрать только одну. Переключатели создаются элементом <input type=»radio» .

Выбор или нажатие на одну из них также представляет событие click :

При создании группы переключателей их атрибут name должен иметь одно и то же значение. В данном случае это — languages . То есть переключатели образуют группу languages .

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

Значение выбранного переключателя также можно получить через объект Event : e.target.value

Флажок

Каждый переключатель также, как и флажок, имеет свойство checked , которое возвращает значение true , если переключатель выбран. Например, отметим последний переключатель:

10.5. Список

Для создания списка используется HTML-элемент select . Причем с его помощью можно создавать как выпадающие списки, так и обычные с одинарным или множественным выбором.

Атрибут size позволяет установить, сколько элементов будут отображаться одномоментно в списке. Значение size=»1″ отображает только один элемент списка, а сам список становится выпадающим. Если установить у элемента select атрибут multiple , то в списке можно выбрать сразу несколько значений.

Каждый элемент списка представлен HTML-элементом option , у которого есть отображаемая метка и есть значения в виде атрибута value .

В JavaScript элементу select соответствует объект HTMLSelectElement , а элементу option — объект HtmlOptionElement или просто Option .

Все элементы списка в JavaScript доступны через коллекцию options . А каждый объект HtmlOptionElement имеет свойства: index , text (отображаемый текст) и value (значение элемента). Например, получим первый элемент списка и выведем о нем через его свойства всю информацию:

Поля выбора

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

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

За добавление в коде JavaScript отвечает функция addOption() , в которой получаем введенные в текстовые поля значения, создаем новый объект Option и добавляем его в массив options объекта списка.

За удаление отвечает функция removeOption() , в которой просто получаем индекс выделенного элемента с помощью свойства selectedIndex и в коллекции options приравниваем по этому индексу значение null .

Поля выбора

Для добавления/удаления также в качестве альтернативы можно использовать методы элемента select :

10.5.1. События элемента select

Элемент select поддерживает три события:

blur потеря фокуса

focus получение фокуса

change изменение выделенного элемента в списке.

Рассмотрим применение события select :

11. Хранение данных

11.1. Куки

Одну из возможностей сохранения данных в JavaScript представляет использование куки. Для работы с куками в объекте document предназначено свойство cookie .

Для установки куков достаточно свойству document.cookie присвоить строку с куками:

В данном случае устанавливается кука, которая называется login и которая имеет значение tom32 . И в большинстве браузеров мы можем посмотреть ее, узнать всю информацию о ней и в дальнейшем ее можно использовать в приложении:

Установка куки в JavaScript

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

имя куки

значение

срок окончания действия ( expires )

путь ( path )

домен ( domain )

Выше использовались только два параметра: имя куки и значение. То есть в случае со строкой «login=tom32;» куки имеет имя login и значение tom32 .

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

И в этом случае нам надо установить параметр expires , то есть срок действия куков:

То есть срок действия куки login истекает в понедельник 30 августа 2021 года в 00:00. Формат параметра expires очень важен. Однако его можно сгенерировать программно. Для этого мы можем использовать метод toUTCString() объекта Date :

В данном случае срок действия куки будет составлять 4 часа.

Если вдруг нам надо установить куки для какого-то определенного пути на сайте, то мы можем использовать параметр path . Например, мы хотим установить куки только для пути www.mysite.com/home :

В этом случае для других путей на сайте, например, www.mysite.com/shop , эти куки будут недоступны.

Если на нашем сайте есть несколько доменов, и мы хотим установить куки непосредственно для определенного домена, тогда можно использовать параметр domain . Например, у нас на сайте есть поддомен blog.mysite.com :

Параметр path=/ указывает, что куки будут доступны для всех директорий и путей поддомена blog.mysite.com .

Последний параметр — secure задает использование SSL (SecureSockets Layer) и подходит для сайтов, использующих протокол HTTPS. Если значение этого параметра равно true , то куки будут использоваться только при установке защищенного соединения ssl. По умолчанию данный параметр равен false .

11.1.1. Получение куки

Для простейшего извлечения куки из браузера достаточно обратиться к свойству document.cookie :

Здесь были установлены три куки, и браузер выведет нам все эти куки:

Получить куки в JavaScript

Извлеченные куки не включают параметры expires , path , domain и secure . Кроме того, сами куки разделяются точкой с запятой, поэтому нужно еще провести некоторые преобразования, чтобы получить их имя и значение:

11.2. Web Storage

Хотя куки позволяют сохранять информацию, они имеют ряд ограничений. Например, браузер имеет ограничения на размер куков — каждая кука не может превышать 4 кб. Куки имеют срок действия, после которого удаляются. Куки являются неотъемлемой чертой протокола HTTP и при каждом запросе к серверу передаются вместе с запросом на сервер. Однако для работы с куками на стороне клиента в коде JavaScript не имеет значения передача куков на сервер. Кроме того, для извлечения сохраненных куков надо написать некоторую порцию кода.

Поэтому в HTML5 была внедрена новая концепция для хранения данных — web storage. Web storage состоит из двух компонентов:

session storage

local storage

Session storage представляет временное хранилище информации, которая удаляется после закрытия браузера.

Local storage представляет хранилище для данных на постоянной основе. Данные из local storage автоматически не удаляются и не имеют срока действия. Эти данные не передаются на сервер в запросе HTTP. Кроме того, объем local storage составляет в Chrome и Firefox 5 Мб для домена, а в IE — 10 Мб.

Все данные в web storage представляют набор пар ключ-значение. То есть каждый объект имеет уникальное имя-ключ и определенное значение.

Для работы с local storage в JavaScript используется объект localStorage , а для работы с session storage — объект sessionStorage .

Для сохранения данных надо передать в метод setItem() объекта localStorage :

В этот метод передаются два значения: ключ и значение сохраняемого объекта.

Если в localStorage уже есть объект с ключом login , то его значение заменяется новым.

Для получения сохраненных данных надо вызвать метод getItem() :

В этот метод передается ключ объекта.

Чтобы удалить объект, применяется метод removeItem() , который принимает ключ удаляемого объекта:

И для полного удаления всех объектов из localStorage можно использовать метод clear() :

С сохранением простых объектов все просто, однако при этом надо учитывать, что данные в localStorage сохраняются в виде строки:

Если в данном случае не преобразовать значение к числу с помощью parseInt() , то age будет действовать как строка.

Трудности могут возникнуть с сохранением сложных объектов:

В этом случае нам надо использовать сериализацию в формат JSON:

И в завершении надо сказать, что в некоторых браузерах с помощью специальных инструментов мы можем увидеть сохраненные объекты в local storage. Например, в Google Chrome:

Local Storage в JavaScript

12. Коллекции и итераторы

12.1. Итераторы

Итераторы применяются для организации последовательного доступа к элементам коллекции — массивам, объектам Set и Map . Итераторы предоставляют метод next() , который возвращает два значения: value и done . value хранит собственно значение текущего перебираемого элемента. А свойство done указывает, есть ли еще в коллекции объекты, доступные для перебора.

Некоторые методы коллекций возвращают итераторы. Например, метод entries() , который есть у коллекций Array , Set , Map :

Метод next() возвратит следующий объект на консоль:

Здесь мы видим, что свойство done имеет значение false , так как мы перебрали только один элемент в множестве, и там еще есть два элемента.

Свойство value представляет массив из двух значений. Первое значение представляет ключ или индекс элемента массива, а второй элемент — значение по этому индексу имеет ключ и значение.

Соответственно мы можем организовать и перебор всей коллекции:

Но в этом нет смысла, поскольку все коллекции, возвращающие итераторы, поддерживают перебор с помощью цикла for …​ of , который как раз и использует итератор для получения элементов:

Если мы хотим извлечь еще и индекс элемента в массиве, то мы можем использовать для перебора итератор из entries() :

12.2. Генераторы

Генераторы представляют особый тип функции, которые используются для генерации значений. Для определения генераторов применяется символ звездочки * , который ставится после ключевого слова function . Например, определим простейший генератор:

Функция getNumber() представляет генератор. Функция генератора возвращает итератор. Для получения значения из генератора применяется оператор yield . То есть фактически в данном случае генератор генерирует число 5 .

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

Для перехода к следующему значению применяется метод next() . Если мы посмотрим на консольный вывод, то мы увидим, что данный метод возвращает следующие данные:

То есть по сути возвращается объект, свойство value которого содержит собственно сгенерированное значение. А свойство done указывает, достигли ли мы конца генератора.

Теперь изменим код:

Здесь обращение к методу next() происходит два раза:

Но функция генератора getNumber() генерирует только одно значение — число 5 . Поэтому при повторном вызове свойство value будет иметь значение undefined , а свойство done — true , то есть работа генератора завершена.

Генератор может создавать множество значений:

То есть при первом вызове метода next() из итератора извлекается значение, которое идет после первого оператора yield , при втором вызове метода next() — значение после второго оператора yield и так далее.

Поскольку для получения значений применяется итератор, то мы можем использовать цикл for …​ of :

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

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

12.2.1. Передача данных в генератор

С помощью next() можно передать в генератор данные.

При втором вызове метода next() :

Мы можем получить переданные через него данные, присвоив результат первого оператора yield :

То есть здесь переменная n будет равна 2 , так как в метод next() передается число 2 .

Далее мы можем использовать это значение, например, для генерации нового значения:

Соответственно, переменная m получить значение, переданное через третий вызов метода next() , то есть число 3 .

12.2.2. Инициализация генератора

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

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

12.3. Множества Set

Множества (sets) представляют структуру данных, которая может хранить только уникальные значения. В JavaScript функционал множества определяет объект Set . Для создания множества применяется конструктор этого объекта:

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

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

Для проверки количества элементов можно использовать свойство size .

12.3.1. Добавление

Для добавления применяется метод add() . Его результатом является измененное множество:

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

Так как метод add() возвращает ссылку на это же множество, то мы можем вызывать методы по цепочке:

12.3.2. Удаление

Для удаления элементов применяется метод delete() :

Причем данный метод возвращает булево значение: true — если элемент удален и false — если удаление не произошло (например, когда удаляемого элемента нет в множестве):

Если необходимо удалить вообще все элементы из множества, то применяется метод clear() :

12.3.3. Проверка наличия элемента

Если нужно проверить, если ли элемент в множестве, то используется метод has() . Если элемент есть, то метод возвращает true , иначе возвращает false :

12.3.4. Перебор множества

Для перебора элементов множества применяется метод forEach() :

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

Также для перебора множества можно использовать цикл for …​ of :

12.4. Map

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

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

В данном случае числа 1 , 2 , 3 являются ключами, а строки a , b , c — значениями.

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

12.4.1. Добавление и изменение элементов

Для добавления или изменения значения применяется метод set() :

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

12.4.2. Получение элементов

Для получения элемента по ключу применяется метод get() , в который передается ключ элемента:

Если map не содержит элемента по заданному ключу, то метод возвращает undefined .

Чтобы избежать возвращения undefined , мы можем проверить наличие элемента по ключу с помощью метода has() . Если элемент по ключу имеется, то метод возвращает true , иначе возвращается false :

12.4.3. Удаление элементов

Для удаления одного элемента по ключу применяется метод delete() :

Для удаления всех элементов используется метод clear() :

12.4.4. Перебор элементов

Для перебора элементов используется метод forEach() :

Метод forEach в качестве параметра получает функцию обратного вызова, которая имеет три параметра. Первый и второй параметры — это соответственно значение и ключ текущего перебираемого элемента, а третий параметр — перебираемый объект Map.

Также для перебора объекта Map можно использовать цикл for …​ of :

Каждый элемент из Map помещается в переменную item , которая в свою очередь представляет массив. Первый элемент этого массива — ключ, а второй элемент — значение элемента.

Также объект Map имеет два дополнительных метода: keys() позволяет перебрать только ключи и values() позволяет перебирать значения элементов. Оба метода возвращают итераторы, поэтому для перебора ключей и значений по отдельности также можно использовать цикл for…​of :

12.5. WeakSet и WeakMap

12.5.1. WeakSet

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

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

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

Для добавления данных в WeakSet применяется метод add() :

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

Для удаления применяется метод delete() , в который передается ссылка на удаляемый объект:

Если надо проверить, имеется ли объект в WeakSet , то можно использовать метод has() , который возвращает true при наличии объекта:

12.5.2. WeakMap

WeakMap представляет развитие коллекции Map . Особенностью WeakMap является то, что все ее элементы должны представлять объекты. При этом объектами должны быть как ключи, так и значения.

Для получения объектов по ключу из WeakMap применяется метод get() :

Для добавления новых объектов или изменения старых применяется метод set() :

Чтобы проверить наличие элемента по определенному ключу, применяется метод has() , который возвращает true при наличии элемента:

Для удаления элемента по ключу применяется метод delete() :

13. AJAX

Современные web-приложение, как правило, разделяются на две части: клиент и сервер. Клиент представляет собой web-страницу с кодом JavaScript. К серверным технологиям относятся Java, PHP, Ruby, Node.js, ASP.NET и т.д., которые получают запрос от клиента, обрабатывают и отправляют в ответ результат обработки.

AJAX представляет технологию для отправки запросов к серверу из клиентского кода JavaScript без перезагрузки страницы. Сам термин расшифровывается как Asynchronous JavaScript And XML. То есть изначально AJAX предполагал асинхронное взаимодействие клиента и сервера посредством данных в формате XML. Хотя сейчас XML во многом вытеснил формат JSON. В любом случае AJAX революционизировал web-среду, позволив создавать динамичные отзывчивые web-приложения.

Поскольку AJAX предполагает взаимодействие клиента и сервера, то для работы с AJAX и в частности этой главы необходим локальный web-сервер. Это может быть любой web-сервер: nginx, Apache, IIS и т.д.

13.1. Объект XMLHttpRequest

Для создания приложений, использующих AJAX, применяются различные способы. Но самым распространенным способом является использование объекта XMLHttpRequest :

После создания объекта XMLHttpRequest можно отправлять запросы к серверу. Но для начала надо вызвать метод open() для инициализации:

Метод open() принимает три параметра: тип запроса ( GET , POST , HEAD , PUT ), адрес запроса и третий необязательный параметр — логическое значение true или false , указывающее, будет ли запрос осуществляться в асинхронном режиме. То есть в данном случае запрос будет иметь тип GET , он будет направляться по адресу http://localhost/hello.txt в синхронном режиме, так как стоит значение false (для асинхронного режима указывается значение true ).

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

Кроме того, метод open() может принимать еще два параметра: логин и пароль пользователя, если для выполнения запроса нужна аутентификация.

После инициализации запроса методом open() необходимо отправить запрос с помощью метода send() :

13.1.1. Свойства XMLHttpRequest

Объект XMLHttpRequest имеет ряд свойств, которые позволяют проконтролировать выполнение запроса:

status : содержит статусный код ответа HTTP , который пришел от сервера. С помощью статусного кода можно судить об успешности запроса или об ошибках, которые могли бы возникнуть при его выполнении. Например, статусный код 200 указывает на то, что запрос прошел успешно. Код 403 говорит о необходимости авторизации для выполнения запроса, а код 404 сообщает, что ресурс не найден и так далее.

statusText : возвращает текст статуса ответа, например, «200 OK»

responseType : возвращает тип ответа. Есть следующие типы:

response : возвращает ответ сервера

responseText : возвращает текст ответа сервера

responseXML : возвращает xml , если ответ от сервера в формате xml

Например, выполним запрос к текстовому файлу, который находится на локальном web-сервере. Для выполнения AJAX-запросов потребуется запущенный локальный web-сервер, на котором будет лежать файл hello.txt , в котором будет содержаться одна строка: Привет мир .

Код web-страницы (пусть она называется test.html ) будет следующим:

И после загрузки страницы выполнится ajax-запрос к ресурсу http://localhost:8080/hello.txt . Но важно отметить, что получение статуса сразу после вызова метода request.send() будет работать только для синхронного запроса.

XMLHttpRequest в JavaScript

13.1.2. Асинхронные запросы

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

Работа с асинхронными запросами чуть более сложна, чем с синхронными, поскольку нам надо еще обработать событие readystatechange объекта XMLHttpRequest .

При асинхронном запросе объект XMLHttpRequest использует свойство readyState для хранения состояния запроса. Состояние запроса представляет собой число:

0 : объект XMLHttpRequest создан, но метод open() еще не был вызван для инициализации объекта

1 : метод open() был вызван, но запрос еще не был отправлен методом send()

2 : запрос был отправлен, заголовки и статус ответа получены и готовы к использованию

3 : ответ получен от сервера

4 : выполнение запроса завершено (даже если получен код ошибки, например, 404 )

Событие readystatechange возникает каждый раз, когда изменяется значение свойства readyState . Например, выполним асинхронный запрос:

Кроме обработки события readystatechange для получения ответа сервера можно также обрабатывать событие load , которое возникает после выполнения запроса. Его использование аналогично:

13.2. Отправка данных

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

13.2.1. Отправка GET-запроса

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

Для отправки берем свойства объекта user и формируем из их значений сроку с параметрами:

Затем эта строка добавляется к строке запроса в методе open(«GET», «http://localhost:8080/postdata.php?»+body)

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

Конкретная технология стороны сервера тут не важна. И в качестве тестирования можно взять любую другую технологию. Например, ASP.NET MVC . Метод контроллера в ASP.NET MVC , который принимает данные, мог бы выглядеть следующим образом:

13.2.2. Кодирование параметров

Все отправляемые в GET-запросе параметры разделяются знаком амперсанда ( & ). Но что, если какой-нибудь параметр имеет знак амперсанда. Например,

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

При этом строка Tom&Tim будет кодирована в следующую строку: Tom%26Tim .

При необходимости мы можем выполнить обратное декодирование с помощью функции decodeURIComponent() :

13.2.3. POST-запросы

Отправка данных в POST-запросах будет немного отличаться:

Для отправки данных методом POST надо установить заголовок Content-Type с помощью метода setRequestHeader() . В данном случае заголовок имеет значение application/x-www-form-urlencoded .

13.2.4. Отправка форм. FormData

Начиная со спецификации XMLHttpRequest2 в JavaScript появился новый объект — FormData , который позволяет сериализовать данные формы для ее последующей отправки. При этом нам даже необязательно создавать форму в коде HTML, мы можем создать ее динамически в JavaScript:

Для добавления данных у объекта FormData используется метод append(‘имя_параметра’, значение) . При этом никакие заголовки указывать не надо.

Также мы можем определить форму в HTML и использовать ее для отправки:

Для сериализации всех полей формы нам достаточно передать объект формы в конструктор FormData: var formData = new FormData(form) .

13.2.5. Отправка данных в формате json

Для отправки данных в формате json нам необходимо установить соответствующий заголовок и сериализовать данные с помощью метода JSON.stringify() :

13.3. Promise в AJAX-запросах

Как видно из примеров прошлых тем для создания AJAX-запросов используются фактически повторяющиеся вызовы, отличающиеся лишь деталями — строкой запроса, функциями обработки ответа. И вполне было бы неплохо создать для всех действий, связанных с асинхронным AJAX-запросом, создать какую-то общую абстракцию и затем использовать ее при следующих обращениях к серверу.

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

Инкапсулируем асинхронный запрос в объект Promise :

Метод get получает в качестве параметра адрес ресурса сервера и возвращает объект Promise . Конструктор Promise в качестве параметра принимает функцию обратного вызова, которая в свою очередь принимает два параметра — две функции: одна выполняется при успешной обработке запроса, а вторая — при неудачной.

Допустим, на сервере будет размещен файл users.json со следующим содержимым:

Теперь вызовем метод get() для осуществления запроса к серверу:

Для обработки результата объекта Promise вызывается метод then() , который принимает два параметра:

функцию, вызываемую при успешном выполнении запроса

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

Метод then() также возвращает объект Promise . Поэтому при необходимости мы можем применить к его результату цепочки вызовов метода then: get().then().then()…​ . Например:

В данном случае функция в первом вызове метода then получает ответ сервера и возвращает разобранные данные в виде массива с помощью функции JSON.parse() .

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

Для обработки ошибок мы можем использовать метод catch() , в который передается функция обработки ошибок:

Подобным образом через Promise можно было бы отправлять данные на сервер:

Добавить комментарий

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