11 полезных приёмов в JavaScript


Оглавление (нажмите, чтобы открыть):

11 полезных приёмов в JavaScript

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

Конвертирование переменных

Как ни странно, но иногда для конвертирования переменных одного типа в другой используют конструкторы объектов типа Array() или Number(). На самом деле правильнее и лучше (с точки зрения производительности) использовать примитивные типы данных:

Конвертирование в даты (new Date(myVar)) и регулярные выражения (new RegExp(myVar)) нужно делать с использованием конструкторов. Всегда используйте структуру /регулярное_выражение/флаги при создании регулярных выражений.

Конвертирование из десятичной в шестнадцатеричную и восьмеричную системы, и наоборот

Вы пишите отдельные функции для этого? На самом деле все преобразование можно сделать стандартными методами:

Замена всех вхождений подстроки в строку

Часто случается, что нужно заменить все вхождения какой-то строки в другую строку. Вместо громоздких конструкций лучше всего делать так:

Еще несколько преобразований для числовых данных

В добавлении к предыдущим методам:

Определение версии JavaScript

Вы знаете какую версию JavaScript поддерживает ваш браузер? Если нет, то можно посмотреть в Википедии.

Вот небольшой скрипт для определения версии JavaScript:

Использование window.name для простейшей сессии

Записывая строковые переменные в переменную window.name, вы можете сохранять это значение в текущем окне до тех пор, пока оно не закрыто. Это очень полезно, например, для переключения между режимами отладки и тестирования.

Определение наличия переменной

Эта проблема может появиться либо при определении, есть ли переменная в принципе, либо при определении ее типа. Рассмотрим код:

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

Передача аргументов функции

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

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

Использование document.createDocumentFragment()

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

Передача функции в метод replace()

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

Метки внутри циклов

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

Нашли для себя что-то полезное? Отлично! Есть, что добавить — пишите в комментариях.

Автор: Павел Марковнин

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

Иногда пишет в Твиттер, но чаще на Временно.нет.

Расскажите друзьям

Комментарии — 13

if (undefined_var) < . >лично у меня никогда ошибок не вызывало. Насколько я помню, в таком простом случае оператор if проверяет в т.ч. и на существование переменной. # 22 февраля 2010 remal Для несуществующих переменных можно делать так:
myVar = myVar || <>;

Это просто инициализатор массива, никакого приведения типов здесь нет, только создается новый массив с одним элементом:

С числами всё таки лучше работать по человечески:

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

Кстати, еще можно быстро получить timestapm:

Все числа хранятся в формате float64, т.е. 8 байт с плавающей точкой.
Базовые типы: Строки, Числа, Boolean

Для определения наличия свойств объектов (в том числе и window), можно воспользоваться оператором in.

11 полезных приёмов в JavaScript

Освойте бесплатно наиболее простой, быстрый и гибкий способ создавать адаптивные веб-сайты.

Дизайн лендинга

Создавайте дизайн любых сайтов — для себя и на заказ!

Популярное

  • Главная
  • ->
  • Материалы
  • ->
  • 11 ошибок при работе с JavaScript

Reg.ru: домены и хостинг

Крупнейший регистратор и хостинг-провайдер в России.

Более 2 миллионов доменных имен на обслуживании.

Продвижение, почта для домена, решения для бизнеса.


Более 700 тыс. клиентов по всему миру уже сделали свой выбор.

Бесплатный Курс «Практика HTML5 и CSS3»

Освойте бесплатно пошаговый видеокурс

по основам адаптивной верстки

на HTML5 и CSS3 с полного нуля.

Фреймворк Bootstrap: быстрая адаптивная вёрстка

Пошаговый видеокурс по основам адаптивной верстки в фреймворке Bootstrap.

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

Верстайте на заказ и получайте деньги.

Что нужно знать для создания PHP-сайтов?

Ответ здесь. Только самое важное и полезное для начинающего веб-разработчика.

Узнайте, как создавать качественные сайты на PHP всего за 2 часа и 27 минут!

Создайте свой сайт за 3 часа и 30 минут.

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

Вам останется лишь наполнить его нужной информацией и изменить дизайн (по желанию).

Изучите основы HTML и CSS менее чем за 4 часа.

После просмотра данного видеокурса Вы перестанете с ужасом смотреть на HTML-код и будете понимать, как он работает.

Вы сможете создать свои первые HTML-страницы и придать им нужный вид с помощью CSS.

Бесплатный курс «Сайт на WordPress»

Хотите освоить CMS WordPress?

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

Научитесь работать с темами и нарезать макет.

Бесплатный видеокурс по рисованию дизайна сайта, его верстке и установке на CMS WordPress!

Хотите изучить JavaScript, но не знаете, как подступиться?

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

Развеются мифы о сложности работы с этим языком, и Вы будете готовы изучать JavaScript на более серьезном уровне.

*Наведите курсор мыши для приостановки прокрутки.

11 ошибок при работе с JavaScript

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

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

Ошибка № 1 — Вы используете глобальные переменные

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

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

В действительности, нет.

Эта идея плоха тем, что вы можете непреднамеренно переписать содержимое ваших переменных.

Скажем, у вас есть интернет-магазин, и вы используете JavaScript для того, чтобы отображать цены всех товаров в корзине с покупками (разумеется, вы все это пересчитываете на стороне сервера; JavaScript же используется как декоративная примочка). Ваш код в этом случае может выглядеть примерно так:

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

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

Ваш код теперь будет работать с неверными данными, а вы рискуете потратить кучу времени и нервов, пока обнаружите ошибку и устраните ее.

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

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

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

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

И еще один момент по глобальным переменным: если вы не используете ключевое слово var при создании переменной, то JavaScript в этом случае по умолчанию создаст глобальную переменную:

Переменная tax доступна за пределами функции потому что объявлена без использования ключевого слова var. Будьте внимательны!

Ошибка № 2 — Вы не используете точку с запятой (;)

Каждая команда в JavaScript должна завершаться точкой с запятой. Очень просто. Если вы не поставите точку с запятой, то за вас это сделает компилятор.

Отсюда вопрос: зачем нам тратить время, если компилятор все равно сделает все за нас?

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

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

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

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

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

Решением будет такой подход:

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

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

Ошибка № 3 — Вы используете ==


Встаньте прямо сейчас из-за монитора и прогуляйтесь, пока не встретите первого попавшегося JavaScript-разработчика. Попросите его/ее назвать вам одну типичную ошибку при работе с JavaScript и он/она скажет: «Использование двойного знака равенства вместо тройного».

Что это означает?

Испробуйте такой код:

Работает именно так, как вы и ожидали, верно? Теперь попробуйте следующее:

Да, вы снова получаете слова Это верно! в консоли. и да, это плохо.

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

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

Очевидно, все то же самое применимо и к операторам != и !==.

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

Ошибка № 4 — Вы используете «объектные обертки»

JavaScript любезно (хм?) предоставляет нам возможность использовать «объектные обертки» для простого (хм?) создания примитивных типов:

Прежде всего, это просто супер неудобно. Все эти вещи можно сделать куда меньшим количеством кода:

Однако, постойте! Это не одно и то же.

Это значит, что если проверить тип для Number(10) или String(«hello») с помощью typeof, то мы получим object — не то, что ожидаем. К тому же, использование «объектных оберток» может привести к неожиданному поведению программы, отличному от ее поведения при работе с примитивными значениями.

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

Примитивные значения в действительности не имеют методов (т.к. не являются объектами). Поэтому, когда вы вызываете метод примитивного объекта (вроде «hello».replace(«ello», «i»)), JavaScript создает «объектную обертку» для строки, делает то, что вам нужно, после чего удаляет объект.

Оставьте «объектные обертки» для JavaScript и пользуйтесь примитивными значениями.

Примечание: возможно, это лишнее, но я хочу донести до новичков следующее: я не говорю, что вам не следует использовать функцию-конструктор и ключевое слово new (хотя некоторые рекомендуют именно это). Этот совет применим к примитивным типам данных: числам, строкам; к массивам и пустым объектам.

Ошибка № 5 — Вы не проверяете свойства при использовании for-in

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

Если вы делали это ранее, то использовали цикл for-in:

Если вы выполните код выше, то получите такой вывод:

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

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

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

В любом случае, будьте внимательны при использовании for-in, чтобы избежать нежелательных результатов.

Ошибка № 6 — Вы используете with или eval

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

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

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

Первый пункт пояснений не требует, поэтому переходим ко второму.

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

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

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

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

А что же насчет eval?

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

Звучит безобидно, скорее даже радует своими возможностями, верно? В этом-то и заключается основная проблема: это слишком мощная штука.

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

— вы можете просто написать непосредственно код;
eval замедляет работу скрипта, как и with.

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

Вы действительно хотите дать посетителям вашего сайта полный контроль над своим кодом? Надеюсь, что нет.

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

Ошибка № 7 — Вы игнорируете основание системы счисления при использовании функции parseInt

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

Хм, что же тут произошло? Разве во второй строке должно быть не 43?

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

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

Ошибка № 8 — Вы не используете фигурные скобки при работе с if и while

Одна из очевидных привлекательных сторон JavaScript — его гибкость. Однако иногда это может сыграть с вами злую шутку.

Речь идет о фигурных скобках для конструкций if и while. Они необязательны, если у вас в блоке кода только одна строка:

Это здорово, потому что вы можете даже разместить все необходимое в одну строку:

Но это не очень здорово по двум причинам: первая — это может выглядеть неочевидно:

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

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

Ошибка № 9 — Вы добавляете элементы в DOM поштучно

Мастер Йода рекомендует:  Искусственный интеллект научили ориентироваться в Нью-Йорке


Ок, ок, это не совсем JavaScript, но в 99 случаях из 100 использование JavaScript подразумевает работу с DOM (Document Object Model — Объектная Модель Документа).

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

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

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

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

Быстрее, четче, понятнее — почему не полюбить?)

Ошибка № 10 — Вы не изучаете JavaScript

JavaScript не равняется jQuery. Я вас удивил?

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

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

Не будьте одним из таких людей: вокруг множество добротных уроков и руководств, поэтому не ищите себе оправдания. Если все, что вы знаете — это jQuery (или Mootools, или еще что-нибудь), то вы ставите себя в неудобное положение.

Ошибка № 11 — Вы следуете всем правилам

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

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

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

К примеру, все отговаривают вас использовать eval, однако это единственный инструмент, с помощью которого вы можете обработать JSON-ответ от сервера. Разумеется, нужно использовать различные проверки для обеспечения безопасности и т.д. Но суть остается той же — вам не нужно бояться «плохих практик», если у вас действительно возникает в них необходимость.

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

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

По материалам http://net.tutsplus.com
Перевод: Дмитрий Науменко

P.S. Присмотритесь к премиум-урокам по различным аспектам сайтостроения, включая JavaScript, jQuery и Ajax, а также к бесплатному курсу по созданию своей CMS-системы на PHP с нуля. Все это поможет вам быстрее и проще освоить практические навыки веб-программирования:

Понравился материал и хотите отблагодарить?
Просто поделитесь с друзьями и коллегами!

12 хитростей JavaScript, которых вы не найдете в большинстве уроков

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

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

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

Итак, вот 12 изящных способов написания более лаконичного и производительного кода.

1. Фильтр уникальных значений

Тип Set был введен в ES6, и наряду с оператором «spread» . мы можем использовать его для создания нового массива с уникальными значениями.

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

Этот трюк работает для массивов, содержащих примитивные типы: undefined, null, boolean, string и number. (Если бы у вас был массив, содержащий объекты, функции или дополнительные массивы, вам понадобился бы другой подход!)

2. Кешируем длину массива в циклах

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

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

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

Этот код почти такой же лаконичный, как и приведенный выше, но он работает таким образом, что при увеличении размера массива мы не теряем время на перепроверку array.length .

3. Вычисление короткого замыкания

Тернарный оператор — это быстрый способ написать простые (а иногда и не очень простые) условные конструкции, например:

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

Как это работает

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

Использование && вернет первое false или ‘ложноe’ значение. Если каждый операнд оценивается как true, будет возвращено последнее вычисленное выражение.

Использование || вернет первое true или ‘правдивоe’ значение. Если каждый операнд оценивается как false , будет возвращено последнее вычисленное выражение.

Пример 1

Допустим, мы хотим вернуть свойство length переменной, но мы не знаем её тип.

Мы можем использовать оператор if/else оператор для проверки, что foo это приемлемый тип, однако это может быть довольно долго. Короткое замыкание позволяет сделать это таким образом:

Если переменная foo имеет свойство length, оно будет возвращено. В противном случае вернется length пустого массива: 0.

Пример 2

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

Допустим, мы хотели получить доступ к свойству data , которое находится внутри this.state , но data — undefined до тех пор, пока программа не вернет респонз.

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

Это кажется довольно скучным. Оператор «или» предоставляет более краткое решение:

Мы не можем изменить код выше, чтобы использовать && . Утверждение ‘Fetching Data’ && this.state.data вернется this.state.data независимо от того, равно оно undefined или нет. Это потому, что ‘Fetching Data’ «правдиво», и поэтому && всегда будет пропускать его, когда он указан первым.

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

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

Например, мы могли бы привести свой пример выше к this.state.data?.() — вернет data, только если оно не null .

Или, если мы сомневаемся в переменной state , мы могли бы вернуть this.state?.data .

Предложение в настоящее время находится на Stage 1 в качестве экспериментальной функции. Вы можете прочитать об этом тут, и можете использовать его в своем JavaScript через Babel, добавив @babel/plugin-proposal-optional-chaining в ваш .babelrc файл.


4. Преобразование в Boolean

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

Если не указано иное, все значения в JavaScript являются «правдивыми» за исключением 0, «», null, undefined, NaN и, конечно false — которые являются «falsy».

Мы можем легко переключаться между true и false, используя отрицательный оператор !, который также преобразует тип в «boolean» .

Этот тип преобразования типов может быть полезен в условных выражениях, хотя единственная причина, по которой вы бы решили определить false как !1, это если бы вы играли в code golf!

5. Преобразование в String

Чтобы быстро преобразовать число в строку, мы можем использовать оператор конкатенации + , за которым следует пустой набор кавычек «» .

6. Преобразование в Number

Обратное можно быстро сделать с помощью оператора сложения + .

Это также может быть использовано для преобразования boolean в числа, как показано ниже:

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

Тильда, известная как «побитовый оператор НЕ», является оператором, эквивалентным -n — 1 . Так, например,

Использование двух тильд подряд отрицает операцию, потому что — ( — n — 1) — 1 = n + 1 — 1 = n . Другими словами,

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

7. Быстрое возведение в степень

Начиная с ES7 стало возможным использовать оператор возведения в степень ** как сокращение для степеней, что быстрее, чем запись Math.pow(2, 3). Это простой материал, но он попал в список, потому что не так много учебных содержит этот оператор!

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

До ES7 сокращение существовало только для степеней с основанием 2 с использованием оператора побитового сдвига влево FrontEndDev и Web Stack в Telegram, чтобы не пропустить самое интересное из мира Web!

Продвинутая работа с событиями в JavaScript

Учебник JavaScript

Практика

Работа с DOM

Практика

Некоторые продвинутые вещи

Рекомендованное ES6

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

Регулярки

Разное

Работа с канвасом

Практика

  • урок исключен (мало материала), по аяксу скоро будет отдельный учебник (много материала)
    Работа с
    AJAX в JavaScript
    Работа с
    AJAX + PHP

Контекст

Drag-and-Drop

  • Урок №
    Введение
    в ООП в стиле ES6
  • Урок №
    Основы
    работы с ООП
  • Урок №
    Наследование
    классов в JavaScript
    Продвинутая работа
    с классами на JavaScript
  • Урок №
    Применение
    ООП при работе с DOM
  • Урок №
    Практика
    по ООП в JavaScript
  • Тут скоро будут еще уроки
    по функциональному и прототипному
    стилю ООП.

Практика по ООП

Ваша задача: посмотрите, попробуйте повторить.

Практика

Promise ES6

Библиотека jQuery

Тк. jQuery устаревает, объявляю эти уроки не обязательными и выношу в конец учебника (так по уровню уроки середины учебника, если что). В перспективе переедет в отдельный учебник по jq.

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

События через атрибуты

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

Напомню еще раз этот способ на примере: сейчас по клику на кнопку сработает функция func, которая выводит на экран alert:

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

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

События через работу с атрибутами


По сути атрибут onclick является таким же атрибутом, как, к примеру, value. И, если мы могли менять атрибут value таким образом — elem.value, то точно также мы можем менять атрибут onclick.

Если мы сделаем так: elem.onclick = func, то привяжем к элементу elem функцию func. Посмотрите пример и под ним мы обсудим все нюансы этого способа:

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

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

Теперь, зная эту страшную тайну, вернемся к строке elem.onclick = func — в данном случае я в атрибут onclick записываю исходный код функции, а не ее результат — и все работает. Если вы сделаете так — elem.onclick = func() — то запишите результат функции и ничего не будет работать.

Кстати, результатом функции func() будет undefined, так как у нее нет команды return. Напомню код функции, о которой идет речь:

Давайте вспомним метод setInterval (см. урок работа с таймерами в JavaScript), когда мы использовали его таким образом window.setInterval(timer, 1000) — в этом случае мы также писали функцию timer без круглых скобок, потому что нас интересовал не результат работы функции, а ее код.

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

Достоинства и недостатки такого способа

Давайте теперь обсудим достоинства и недостатки этого способа.

Достоинства

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

Давайте сделаем это. Получим все инпуты с помощью getElementsByTagName и в цикле привяжем каждому такое событие: пусть по клику каждый инпут выдает алертом текст ‘!’:

Теперь нажатие на любой инпут будет приводить к тому, что будет срабатывать функция func, которая алертом выводит ‘!’.

Использование this

Давайте усложним задачу и сделаем так, чтобы alert выводил содержимое атрибута value того инпута, на который кликнули мышкой.

Для этого нужно воспользоваться this, только не так, как мы это делали раньше. Раньше, когда мы писали событие прямо в атрибут, мы делали так: onclick=»func(this)», однако сейчас вот так — elems[i].onclick = func(this) — мы сделать не можем.

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

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

Вы можете спросить, почему тут — onclick=»func()» — в функции написаны круглые скобки, хотя по логике там тоже требуется исходный код, а не результат. Об этом вы узнаете в уроке про анонимные функции чуть позже.

Так как правильно использовать this в нашей конструкции elems[i].onclick = func? На самом деле тут this доступен внутри функции func и он ссылается на тот элемент, в котором возникло событие, вызвавшее эту функцию. То есть, если я делаю клик по первому инпуту — в this будет лежать ссылка на него, а если по второму — то на него.

В данном случае считайте, что this — это будто переменная elem, полученная через getElementById. К примеру, elem.value позволяет обратиться к атрибуту value, значит this.value будет делать то же самое.

Итак, давайте все-таки решим нашу задачу — сделаем так, чтобы alert выводил содержимое атрибута value того инпута, на который кликнули мышкой:

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

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

Напоминаю правильный вариант:

Недостатки

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

В следующем примере мы пытаемся привязать к событию onclick сразу две функции func1 и func2. Однако по клику на элемент сработает только вторая функция, так как она затрет первую:

В принципе, эту проблему легко обойти, если ввести еще и третью функцию func3. Привяжем к атрибуту onclick только func3, а она пусть вызывает func1 и func2 у себя внутри:

Как вы видите, этот недостаток не слишком существенный и его легко обойти. Только что вводится лишняя функция, что немного неудобно.

Однако, есть еще один недостаток — мы не можем легко отвязать от onclick, к примеру, только функцию func1, оставив func2 привязанным. Можно, конечно же, накрутить большие конструкции кода, однако это не нужно, если пользоваться еще более продвинутым способом привязать событие — через addEventListener. Давайте посмотрим, как с работать с этой функцией:

Работа с addEventListener

Метод addEventListener первым параметром принимает название события, а вторым — функцию, которую нужно привязать к этому событию. При этом имя события пишется без ‘on’: ‘click’ вместо ‘onclick’, ‘mouseover’ вместо ‘onmouseover’ и так далее. Имя функции (второй параметр) пишется без кавычек и без круглых скобок (зачем это нужно, мы с вами уже разобрали выше).

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

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

Если вы скопируете этот код и запустите его у себя — сработает и функция func1, и функция func2.

Работа с this для addEventListener

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

Давайте посмотрим на примере: привяжем к кнопке событие onclick, которое будет запускать функцию func. Эта функция будет выводить на экран value нашей кнопки:

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

Здесь удобство работы с this в том, что не нужно создавать разные функции для разных элементов. Есть одна функция func, которая делает одно и то же, но для разных элементов и различаем мы их через this — на какой элемент кликнули — тот элемент и будет в this.

Ну, а сейчас получим массив кнопок с помощью getElementsByTagName и каждой из них привяжем функцию func.

В this будет лежать ссылка на ту кнопку, на которую вы нажали, и функция func выведет на экран именно ее value:

Удаление привязки через removeEventListener

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

Мастер Йода рекомендует:  Как работает инструмент Google для отказа от ссылок

Давайте привяжем к элементу 3 функции: func1, func2 и func3, которые будут выводить на экран числа 1, 2 и 3:

А теперь сразу же после привязки отвяжем функции func1 и func2. Это делается с помощью метода removeEventListener, которая принимает те же параметры, что и addEventListener:

Если вы запустите этот пример, то увидите, что сработает функция func3, а первые две — нет.

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

Пусть при первом клике на кнопку сработают все 3 функции и при этом func1 и func2 отвяжутся от элемента. И при следующих кликах будет срабатывать только функция func3, которую мы не отвязываем.

Обратите внимание на this внутри функции — он указывает на наш элемент.

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

Что вам делать дальше:

Приступайте к решению задач по следующей ссылке: задачи к уроку.

Когда все решите — переходите к изучению новой темы.

11 полезных приёмов в JavaScript


22 февраля 2010

Неплохой материал, собравший довольно большое количество мелких приёмов. Среди них «приведение» типов, перевод чисел в различные системы счисления, организация сессии посредством window.name, пакетная вставка в DOM и использование callback при замене по регулярному выражению.

Комментарии RSS по email OK

не думал сделать человеческой длины блог(500-600px текстовую область) а не 100%?

а то на 1680 лол! ок 😉

Очень даже думал. Сразу после обновления начинки сделаю.

9 полезных приёмов для тех, кто программирует на JavaScript

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

1. Очистка или усечение массива

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

2. Имитация именованных параметров при деструктурировании объекта

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

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

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

3. Деструктурирование и элементы массивов

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

4. Использование диапазонов значений в операторе switch

Вот простой приём, демонстрирующий использование диапазонов значений в операторе switch :

5. Организация ожидания выполнения нескольких асинхронных функций в конструкции async/await

Благодаря следующему приёму, в котором используется Promise.all , можно организовать ожидание выполнения нескольких асинхронных функций:

6. Создание чистых объектов

При необходимости можно создать абсолютно пустой, чистый объект, который не наследует никаких свойств и методов от Object (например — это constructor , toString() и так далее). Вот как это сделать:

7. Форматирование JSON-кода

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

8. Удаление дублирующихся элементов массивов

Использование объекта типа Set из ES2015 с оператором расширения позволяет легко и удобно удалять из массивов дублирующиеся элементы:

9. Линеаризация многомерных массивов

Линеаризация массивов с использованием оператора расширения — это предельно простая задача:

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

Итоги

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

Уважаемые читатели! Знаете какие-нибудь неочевидные вещи, которые могут пригодиться JS-разработчикам? Если так — просим о них рассказать.

Замыкания в JavaScript

Это перевод статьи Притти Кассириди «Let’s Learn JavaScript Closures».

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

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

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

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

Что такое замыкания?

Замыкания являются мощным инструментом в JavaScript и других языках программирования. Вот определение с MDN:

Замыкания — это функции, ссылающиеся на независимые (свободные) переменные. Другими словами, функция, определённая в замыкании, «запоминает» окружение, в котором она была создана.

Заметка: cвободные переменные — это переменные, которые не объявлены локально и не передаются в качестве параметра.

Давайте посмотрим на несколько примеров:

Пример 1

В примере функция numberGenerator создаёт локальную «свободную» переменную num (число) и checkNumber (функция, которая выводит число в консоль). Функция checkNumber не содержит собственной локальной переменной, но благодаря замыканию она имеет доступ к переменным внутри внешней функции, numberGenerator. Поэтому объявленная в numberGenerator переменная num будет успешно выведена в консоль, даже после того, как numberGenerator вернёт результат выполнения.

Пример 2

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

Обратите внимание, как переменная hello определяется после анонимной функции, но эта функция всё равно может получить доступ к этой переменной hello. Это происходит из-за того, что переменная hello во время создания уже была определена в области видимости (scope), тем самым сделав её доступной на тот момент, когда анонимная функция будет выполнена. Не беспокойтесь, позже я объясню, что такое «область видимости». А пока просто смиритесь с этим.

Понимаем высокий уровень

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

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

Контекст выполнения

Контекст выполнения — это абстрактное понятие, которое используется в спецификации ECMAScript для оценки времени выполнения кода. Это может быть глобальный контекст — global context, в котором ваш код выполнится первым, или когда поток выполнения переходит в тело функции.

В любой момент времени выполняется только один контекст функции (тело функции). Вот почему JavaScript является однопотоковым, так как единовременно может выполняться только одна команда. Обычно браузеры поддерживают этот контекст с помощью стека — stack. Стек — структура данных, выполняемая в обратном порядке: LIFO — «последним пришёл — первым вышел». Последнее, что вы добавили в стек, будет удалено первым из него. Это происходит из-за того, что мы можем только добавить или удалить элементы из верхушки стека. Текущий или «выполняющийся» контекст исполнения — всегда верхний элемент стека. Он выскакивает из стека, когда код в текущем контексте полностью разобран, позволяя следующему верхнему элементу стека взять на себя контекст выполнения.

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

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


Затем, когда boop возвратится, он удалится из стека, и bar продолжит работу:

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

  • Оценка состояния кода — любое состояние необходимо выполнить, приостановить и возобновить определение кода, связанного с этим контекстом выполнения.
  • Функция — объект функции, который оценивает контекст выполнения или null, если контекст был определён как script или модуль.
  • Область — набор внутренних объектов, глобальное окружение ECMAScript, весь код ECMAScript, который находится в пределах этого глобального окружения и другие связанные с ним состояния и ресурсы.
  • Лексическое окружение — используется для разрешения ссылок идентификатора кода в этом контексте исполнения.
  • Переменное окружение — лексическое окружение, чья запись окружения — EnvironmentRecord имеет связи, созданные заявленными переменными — VariableStatements в этом контексте выполнения.

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

Заметка: c технической точки зрения, окружение переменных и лексическая область видимости используются для реализации замыканий. Но для простоты мы заменим его на «окружение». Для детального объяснения разницы между лексическим и переменным окружением читайте статью Акселя Раушмайера.

Лексическая область видимости

Дадим определение: лексическое окружение — специфичный тип, используемый для связи идентификаторов с определёнными переменными и функциями на основе лексической структуры вложенности кода ECMAScript. Лексическое окружение состоит из записи окружения и, возможно, нулевой ссылки на внешнее лексическое окружение. Обычно лексическое окружение связано с определённой синтаксической структурой, например: FunctionDeclaration — объявление функции, BlockStatement — оператор блока, Catch clause — условный оператор, TryStatement — перехват ошибок и новым лексическим окружением, которое создавалось каждый раз при разборе кода. — ECMAScript-262/6.0

Давайте разберём это.

  • «используемый для связи идентификаторов»: целью лексического окружения является управление данными, то есть идентификаторами в коде. Говоря иначе, это придаёт им смысл. Например, у нас есть такая строка в консоли: console.log(x / 10), x здесь бессмысленная переменная или идентификатор без чего-либо, что придавало бы ей смысл. Лексическое окружение обеспечивает смысл или «ассоциацию» через запись окружения. Смотрите ниже.
  • Лексическое окружение состоит из записи окружения: запись окружения — причудливый способ сказать, что она хранит записи всех идентификаторов и связей, которые существуют в лексической области видимости. Каждая лексическая область видимости имеет собственную запись окружения.
  • Лексическая структура вложенности: самый интересный момент, который говорит, что внутреннее окружение ссылается на внешнее окружение, и это внешнее окружение может иметь собственное внешнее окружение. В результате окружение может быть внешним окружением для более чем одного внутреннего окружения. Глобальное окружение является единственным лексическим окружением, которое не имеет внешнего окружения. Это сложно описать словами, поэтому давайте использовать метафоры и представим лексическое окружение как слои лука: глобальная среда — внешний слой луковицы, где каждый последующий слой находится ниже.

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

  • Новое лексическое окружение, которое создавалось каждый раз при разборе кода — каждый раз, когда вызываются внешние вложенные функции, создаётся новое лексическое окружение. Это важно, и мы вернёмся к этому моменту в конце. Примечание: функции — не единственный способ создать лексическое окружение. Другие типы содержат в себе оператор блока — block statement или условный оператор — catch clause. Для простоты, я сосредоточусь на окружении созданной нами функции на протяжении всего поста.

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

Цепочки областей видимости

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

Давайте рассмотрим эту структуру вложенности:

Как вы можете видеть, bar вложен в foo. Чтобы всё это представить посмотрите на диаграмму ниже:

Мы вернёмся позже к этому примеру.

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

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

Идём в обход: динамическая область видимости против статической области видимости

У динамических языков программирования существует стековая архитектура — stack-based implementations, локальные переменные и функции хранятся в стеке. Поэтому, во время выполнения стека, программа определяет какую переменную вы имеете в виду. С другой стороны, статическая область видимости — это когда переменные ссылаются на контекст и фиксируются на момент создания. Другими словами, структура исходного кода программы определяет к каким переменным вы обращаетесь.

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

Пример 1

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

В статической области видимости возврат значения bar зависит от значения x. Это происходит из-за того, что статическая и лексическая структура исходного кода приводит x и к 10, и к 15.

Динамическая область видимости даёт нам стек определённых переменных, которые отслеживаются во время выполнения. Поэтому x, которую мы используем, зависит от того, что находится в её области видимости и как она была динамично определена во время выполнения. Выполнение функции bar выталкивает x = 2 на верхушку стека, заставляя foo вернуть 7.

Пример 2

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

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

Замыкания

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

Каждая функция имеет контекст выполнения, который состоит из окружения и передаёт смысл в переменные этой функции и ссылку на окружение своего родителя. Эта ссылка делает все переменные в родительской области доступными для всех внутренних функций, независимо от того, вызывается ли внутренняя функция (или функции) вне или внутри области видимости, в которой они были созданы.

Кажется, как будто функция «запоминает» это окружение, поскольку функция буквально имеет ссылку к области видимости и переменным, определённым в этой среде.

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

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

Когда мы вызываем функцию test, мы получаем 45, и она возвращает значение из вызова функции bar (потому что foo возвращает bar). bar имеет доступ к свободной переменной y даже после того, как функция foo вернётся, так как bar имеет ссылку на y через его внешнее окружение, которое является окружением foo! bar так же имеет доступ к глобальной переменной x потому, что у окружения foo есть доступ к глобальному окружению. Это называют «поиск цепочки области видимости».

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

Теперь, когда мы понимаем внутренности на абстрактном уровне, давайте рассмотрим ещё пару примеров:

Пример 1

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

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

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

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

Ура, мы исправили это.

Есть ещё одно решение, в котором мы используем let вместо var, let находится в операторе блока и поэтому новая привязка идентификатора замыкания создаётся для каждой итерации в цикле for.

Пример 2

В этом примере мы покажем как каждый вызов в функции создаёт новое отдельное замыкание:

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

Мастер Йода рекомендует:  8 книг об open source для обучения программированию

Пример 3

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

Это происходит из-за того, что наши функции add и substract ссылаются на среду mysteriousCalculator, и они в состоянии использовать переменные этой среды для расчёта результата.

Пример 4

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

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


  • Контекст выполнения — это абстрактный контекст, использовавшийся в спецификации ECMAScript для отслеживания времени выполнения кода. В любое время может быть только один контекст выполнения, который выполняет код.
  • Каждый контекст исполнения имеет лексическое окружение. Оно содержит связи идентификаторов, то есть переменные и их значения и имеет ссылку на него во внешнем окружении.
  • Набор идентификаторов, к которым у каждого окружения есть доступ, называют «область видимости». Мы можем вложить эти области в иерархическую цепь окружения, известной как «цепочки области видимости».
  • Каждая функция имеет контекст выполнения, который включает в себя лексическое окружение. Это придаёт смысл переменным в пределах этой функции и ссылку на родительское окружение. И это означает, что функции «запоминают» окружение или область видимости, так как они буквально ссылаются на это окружение. Это и есть замыкание.
  • Замыкания создаются каждый раз при вызове внешней функции. Другими словами, внутренняя функция не будет возвращена для замыкания, в котором была создана.
  • Область видимости замыканий в JavaScript лексическая, её смысл определяется статично в зависимости от нахождения в исходном коде.
  • Есть множество практических случаев использования замыканий. Один из важных случаев использования — это сохранение приватных ссылок к переменным во внешней среде.

Замыкающая ремарка

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

Дополнительная литература

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

  • Какие среды переменных бывают в контексте выполнения? Аксель Раушмайер сделал феноменальную работу, объясняющую эту тему, и я просто оставлю ссылку на его пост.
  • Что является различными типами записи окружения?Читайте спецификацию здесь.
  • Отличная статья на MDN про замыканияздесь.

10 ошибок, которые часто допускают новички JavaScript

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

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

1. Пропуск фигурных скобок

Одна из ошибок, которую часто допускают новички JavaScript — пропуск фигурных скобок после операторов типа if, else,while и for . Хотя это не запрещается, вы должны быть очень осторожны, потому что это может стать причиной скрытой проблемы и позже привести к ошибке.

Смотрите пример, приведенный ниже:

Хотя вызов fail() имеет отступ и, кажется, будто он принадлежит оператору if , это не так. Он вызывается всегда. Так что это полезная практика окружать все блоки кода фигурными скобками, даже если в них присутствует только один оператор.

2. Отсутствие точек с запятой

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

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

Так как в строке 3 отсутствует точка с запятой, анализатор предполагает, что открывающаяся скобка в строке 5 является попыткой доступа к свойству, используя синтаксис массива аксессора (смотри ошибку № 8), а не отдельным массивом, который является не тем, что предполагалось.

Это приводит к ошибке. Исправить это просто — всегда вставляйте точку с запятой.

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

3. Непонимание приведений типа

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

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

Проблема может быть легко исправлена с применением parseInt(textBox.value, 10) , чтобы перевести строку в число перед добавлением к ней 10.

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

Чтобы не допустить преобразования типа при сравнении переменных в операторе if , вы можете использовать проверку строгого равенства ( === ).

4. Забытые var

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

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

Вот пример, который кроме того иллюстрирует и другую ошибку — недостающую запятую при объявлении сразу нескольких переменных:

Когда анализатор достигает строки 4, он автоматически добавит точку с запятой, а затем интерпретирует объявления c и d в строке 5, как глобальные.

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

5. Арифметические операции с плавающей точкой

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

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

6. Использование конструкторов вместо оригинальных обозначений

Когда программисты Java и C # начинают писать на JavaScript, они часто предпочитают создавать объекты с использованием конструкторов: new Array(), new Object(), new String() .

Хотя они прекрасно поддерживаются, рекомендуется использовать оригинальные обозначения: [], <>, «» , так как конструкторы имеют свои особенности:

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

7. Непонимание того, как разделяются диапазоны

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

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

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

8. Использование Eval

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

Код внутри eval — это строка. Отладочные сообщения, связанные с Eval-блоками непонятны, и вам придется поломать голову, чтобы правильно расставить одинарные и двойные кавычки.

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

9. Непонимание асинхронного кода


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

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

Вот пример, в котором я использую сервис FreeGeoIP для определения вашего местоположения по IP-адресу:

Несмотря на то, что console.log располагается после вызова функции load() , на самом деле он выполняется перед определением данных.

10. Злоупотребление отслеживанием событий

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

Новичок в этом случае может сделать следующее (используя JQuery ):

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

Повторяющийся вызов button.on(‘click’ ..) приводит к повторяющемуся отслеживанию события, которое никогда не удаляется.

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

Заключение

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

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

Данная публикация представляет собой перевод статьи « 10 Mistakes That JavaScript Beginners Often Make » , подготовленной дружной командой проекта Интернет-технологии.ру

Если вы решили изучить JavaScript

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

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

  • Эрик Фримен, Элизабет Робсон. “Изучаем программирование на JavaScript”. С этой книги рекомендуется начинать новичкам в программирование и JS в частности. Язык книги очень простой, текст постоянно разбавляется забавными картинками и советами. Местами книга вовсе похожа на “комикс”, но это идет ей только на пользу. Профи из тебя книга не сделает (как и любая другая), но фундамент заложит хороший.
  • Николас Заказ. “JavaScript для профессиональных веб-разработчиков”. Отличная толстая книга, которая поможет прокачать свои навыки, полученные после прочтения предыдущей книги. Местами книга устарела (JavaScript быстро развивается), но в этом нет ничего страшного.
  • Дэвид Флэнаган. “JavaScript. Полное руководство”. Наверное это самая толстая книга о JavaScript. Постоянно выходят новые издания и каждый JS разработчик раз в жизни просто обязан ее почитать/полистать.
  • Джон Резиг, Беэр Бибо “Секреты JavaScript ниндзя”. Небольшая книга, которая прекрасно систематизирует знания по JS и учит всяким интересным премудростям.
  • Стоян Стефанов. “JavaScript. Шаблоны”. Если вы успешно усвоили JS на базовом уровне, то самое время приступить к знакомству с шаблонами проектирования. Книга Стояна Стефана поможет справится с этой задачей.
  • Кайл Симпсон. «ES6 & не только«. Новая книга по актуальной версии ES6. Все новшества разбираются на примерах.
  • Николас Закас. «ECMAScript 6 для разработчиков«. Еще одна хорошая по новой версии ECMAScript. Автор в представлении не нуждается.

Ресурсы, статьи

  • Learn JavaScript — современный учебник JavaScript. Если вы решили заняться изучением JavaScript здесь и сейчас, то ресурс LearnJavaScript сможет помочь вам в этом нелегком деле. LearnJavaScript — полноценная книга по JavaScript. Информация постоянно обновляется и актуализируется.
  • MDN — MDN (Mozilla Developer Network). Ресурс, который должен быть в закладках у каждого JS-разработчика.
  • Более 800 ресурсов для front-end-разработчиков;
  • Awesome JavaScript. Подборка полезных ресурсов по изучению JS;
  • JavaScript паттерны…для чайников;
  • JavaScript: ООП, прототипы, замыкания, “класс” Timer.js;
  • Понимание ООП в JavaScript;
  • Перевод книги “Выразительный JavaScript”;
  • Краткое описание всех важных тем, связанных с применением JS. Приведены примеры использования, трюки и т.д.

Видео для JavaScript разработчиков

  • Канал “Академия Яндекса”. JavaScript разработчикам будет полезно посмотреть ШРИ (Школа разработки интерфейсов).
  • Канал “Веб-стандарты”. Видео с различных конференций.
  • uWebDesign обзоры и подкасты про Web-технологии.

Подкасты

  • Радио JS. Пожалуй, лучший русскоязычный подкаст о JS.

Список ресурсов будет постепенно пополняться.

12 хитростей JavaScript, которых вы не найдете в большинстве уроков

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

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

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

Итак, вот 12 изящных способов написания более лаконичного и производительного кода.

1. Фильтр уникальных значений

Тип Set был введен в ES6, и наряду с оператором «spread» . мы можем использовать его для создания нового массива с уникальными значениями.

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

Этот трюк работает для массивов, содержащих примитивные типы: undefined, null, boolean, string и number. (Если бы у вас был массив, содержащий объекты, функции или дополнительные массивы, вам понадобился бы другой подход!)

2. Кешируем длину массива в циклах

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

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

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

Этот код почти такой же лаконичный, как и приведенный выше, но он работает таким образом, что при увеличении размера массива мы не теряем время на перепроверку array.length .

3. Вычисление короткого замыкания

Тернарный оператор — это быстрый способ написать простые (а иногда и не очень простые) условные конструкции, например:

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

Как это работает

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

Использование && вернет первое false или ‘ложноe’ значение. Если каждый операнд оценивается как true, будет возвращено последнее вычисленное выражение.

Использование || вернет первое true или ‘правдивоe’ значение. Если каждый операнд оценивается как false , будет возвращено последнее вычисленное выражение.

Пример 1

Допустим, мы хотим вернуть свойство length переменной, но мы не знаем её тип.

Мы можем использовать оператор if/else оператор для проверки, что foo это приемлемый тип, однако это может быть довольно долго. Короткое замыкание позволяет сделать это таким образом:

Если переменная foo имеет свойство length, оно будет возвращено. В противном случае вернется length пустого массива: 0.

Пример 2

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

Допустим, мы хотели получить доступ к свойству data , которое находится внутри this.state , но data — undefined до тех пор, пока программа не вернет респонз.

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

Это кажется довольно скучным. Оператор «или» предоставляет более краткое решение:

Мы не можем изменить код выше, чтобы использовать && . Утверждение ‘Fetching Data’ && this.state.data вернется this.state.data независимо от того, равно оно undefined или нет. Это потому, что ‘Fetching Data’ «правдиво», и поэтому && всегда будет пропускать его, когда он указан первым.

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

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

Например, мы могли бы привести свой пример выше к this.state.data?.() — вернет data, только если оно не null .

Или, если мы сомневаемся в переменной state , мы могли бы вернуть this.state?.data .

Предложение в настоящее время находится на Stage 1 в качестве экспериментальной функции. Вы можете прочитать об этом тут, и можете использовать его в своем JavaScript через Babel, добавив @babel/plugin-proposal-optional-chaining в ваш .babelrc файл.

4. Преобразование в Boolean

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

Если не указано иное, все значения в JavaScript являются «правдивыми» за исключением 0, «», null, undefined, NaN и, конечно false — которые являются «falsy».

Мы можем легко переключаться между true и false, используя отрицательный оператор !, который также преобразует тип в «boolean» .

Этот тип преобразования типов может быть полезен в условных выражениях, хотя единственная причина, по которой вы бы решили определить false как !1, это если бы вы играли в code golf!

5. Преобразование в String

Чтобы быстро преобразовать число в строку, мы можем использовать оператор конкатенации + , за которым следует пустой набор кавычек «» .

6. Преобразование в Number

Обратное можно быстро сделать с помощью оператора сложения + .

Это также может быть использовано для преобразования boolean в числа, как показано ниже:

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

Тильда, известная как «побитовый оператор НЕ», является оператором, эквивалентным -n — 1 . Так, например,

Использование двух тильд подряд отрицает операцию, потому что — ( — n — 1) — 1 = n + 1 — 1 = n . Другими словами,

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

7. Быстрое возведение в степень

Начиная с ES7 стало возможным использовать оператор возведения в степень ** как сокращение для степеней, что быстрее, чем запись Math.pow(2, 3). Это простой материал, но он попал в список, потому что не так много учебных содержит этот оператор!

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

До ES7 сокращение существовало только для степеней с основанием 2 с использованием оператора побитового сдвига влево FrontEndDev и Web Stack в Telegram, чтобы не пропустить самое интересное из мира Web!

Добавить комментарий