Pipe function in javascript

Функция jQuery(html[,ownerDocument])

Эта function позволяет создавать DOM-узлы в памяти, что называется «на лету», используя HTML-строку, которую можно передать в качестве аргумента. Способ (метод) вызова функции даёт возможность запустить её с помощью двух параметров:
— html — относится к обязательному параметру типа htmlString. По сути, это строка, содержащая HTML-код;
— ownerDocument — относится к необязательным параметрам типа document.

Принцип работы функции:
— анализируется значение параметров;
— если он выглядит, как HTML-код, функция обрабатывает его с помощью метода $.parseHTML();
— после обработки запускается процесс создания DOM-узлов (применяется браузерный механизм .innerHTML);
— в конечном итоге функция возвращает объект jQuery, включающий созданные DOM-узлы.

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

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

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

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

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

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

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

Например:

В коде выше, если вернёт , не выполнит .

Результат функции с пустым или без него –

Если функция не возвращает значения, это всё равно, как если бы она возвращала :

Пустой аналогичен :

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

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

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

Таким образом, это фактически стало пустым .

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

И тогда всё сработает, как задумано.

Координаты в окне: clientX/Y

Все мышиные события предоставляют текущие координаты курсора в двух видах: относительно окна и относительно документа.

Пара свойств содержит координаты курсора относительно текущего окна.

При этом, например, если ваше окно размером 500×500, а мышь находится в центре, тогда и и будут равны 250.

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

Проведите мышью над полем ввода, чтобы увидеть :

В той же системе координат работает и метод , возвращающий координаты элемента, а также .

Координаты курсора относительно документа находятся в свойствах .

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

В IE8- этих свойств нет, но можно получить их способом, описанным в конце главы.

Проведите мышью над полем ввода, чтобы увидеть (кроме IE8-):

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

Устарели:

Некоторые браузеры поддерживают свойства , .

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

Имена переменных

В JavaScript есть два ограничения, касающиеся имён переменных:

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

Примеры допустимых имён:

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

Самое интересное – знак доллара и подчёркивание также можно использовать в названиях. Это обычные символы, как и буквы, без какого-либо особого значения.

Эти имена являются допустимыми:

Примеры неправильных имён переменных:

Регистр имеет значение

Переменные с именами and – это две разные переменные.

Нелатинские буквы разрешены, но не рекомендуются

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

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

Зарезервированные имена

Существует , которые нельзя использовать в качестве имён переменных, потому что они используются самим языком.

Например: , , и зарезервированы.

Приведённый ниже код даёт синтаксическую ошибку:

Создание переменной без использования

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

Это плохая практика, которая приводит к ошибке в строгом режиме:

Подводные камни

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

Рассмотрим код:

Куда будет присвоено значение ?

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

Можно ли в такой ситуации заменить локальную переменную на более короткую? Очевидно, нет:

Такая же опасность для сжатия кроется в использованном . Ведь может обращаться к локальным переменным:

Получается, что при наличии мы не имеем права переименовывать локальные переменные. Причём (!), если функция является вложенной, то и во внешних функциях тоже.

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

Что делать? Разные минификаторы поступают по-разному.

  • UglifyJS – не будет переименовывать переменные. Так что наличие сильно повлияет на степень сжатие кода.
  • GCC – всё равно сожмёт локальные переменные. Это, конечно же, может привести к ошибкам, причём в сжатом коде, отлаживать который не очень-то удобно. Поэтому он выдаст предупреждение о наличии опасной конструкции.

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

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

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

В IE10- поддерживалось условное выполнение JavaScript.

Синтаксис: .

Такой код выполнится в IE10-, например:

Можно хитро сделать, чтобы комментарий остался, например так:

…Однако, с учётом того, что в современных IE11+ эта компиляция не работает в любом случае, лучше избавиться от неё вообще.

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

Ссылки в JS

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

Самый простой метод, позволяющий осуществлять вызов — вывод alert в ссылке. Пример такой ссылки (ссылку можно запустить без проблем из любого браузера):

a href = "javascript:alert('Привет Мир!');">Вызов ссылки/a> 

Второй метод вызова ссылки имеет более сложную конструкцию. В этом случае ссылку можно сделать с помощью функции document.write(). А оформить такую ссылку можно следующим образом:

script type="text/javascript">document.write('текст ссылки');/script>

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

script type="text/javascript">
desiredText = desiredLink =    'http://otus.ru/';
document.write('+desiredLink+'">'+desiredText+'');
/script>

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

Оператор запятая

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

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

Например:

Первое выражение выполняется, а результат отбрасывается. Затем идёт , выражение выполняется и возвращается результат.

Запятая имеет очень низкий приоритет

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

Всё так же, как в

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

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

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

Например:

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

Сравнение с Function Declaration

«Классическое» объявление функции, о котором мы говорили до этого, вида , называется в спецификации языка «Function Declaration».

  • Function Declaration – функция, объявленная в основном потоке кода.
  • Function Expression – объявление функции в контексте какого-либо выражения, например присваивания.

Несмотря на немного разный вид, по сути две эти записи делают одно и то же:

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

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

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

А если бы это было объявление Function Expression, то такой вызов бы не сработал:

Это из-за того, что JavaScript перед запуском кода ищет в нём Function Declaration (их легко найти: они не являются частью выражений и начинаются со слова ) и обрабатывает их.

А Function Expression создаются в процессе выполнения выражения, в котором созданы, в данном случае – функция будет создана при операции присваивания

Как правило, возможность Function Declaration вызвать функцию до объявления – это удобно, так как даёт больше свободы в том, как организовать свой код.

Можно расположить функции внизу, а их вызов – сверху или наоборот.

В некоторых случаях «дополнительное удобство» Function Declaration может сослужить плохую службу.

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

Function Declaration при видны только внутри блока, в котором объявлены. Так как код в учебнике выполняется в режиме , то будет ошибка.

А что, если использовать Function Expression?

Или даже так:

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

Взглянем ещё на один пример – функцию с тремя параметрами:

Строка-вопрос
Функция
Функция

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

Какой-то очень простой код, не правда ли? Зачем, вообще, может понадобиться такая ?

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

Здесь же обратим внимание на то, что то же самое можно написать более коротко:

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

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

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

Такого рода код возникает естественно, он соответствует «духу» JavaScript.

Переменная «arguments»

Все аргументы функции находятся в псевдомассиве под своими порядковыми номерами.

Например:

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

Но у него есть один недостаток. Хотя похож на массив, и его тоже можно перебирать, это всё же не массив. Он не поддерживает методы массивов, поэтому мы не можем, например, вызвать .

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

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

Стрелочные функции не имеют

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

Пример:

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

Оптимизации

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

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

Объединение и сжатие констант

До оптимизации:

После:

  • → .
  • → (научная форма числа, для краткости).
  • → .
  • → без изменений, т.к. результат зависит от .
Укорачивание локальных переменных

До оптимизации:

После оптимизации:

  • Локальная переменная заведомо доступна только внутри функции, поэтому обычно её переименование безопасно (необычные случаи рассмотрим далее).
  • Также переименовываются локальные функции.
  • Вложенные функции обрабатываются корректно.
Объединение и удаление локальных переменных

До оптимизации:

После оптимизации GCC:

  • Локальные переменные были переименованы.
  • Лишние переменные убраны. Для этого сжиматель создаёт вспомогательную внутреннюю структуру данных, в которой хранятся сведения о «пути использования» каждой переменной. Если одна переменная заканчивает свой путь и начинает другая, то вполне можно дать им одно имя.
  • Кроме того, операции и объединены, но это уже другая оптимизация.
Уничтожение недостижимого кода, разворачивание -веток

До оптимизации:

После оптимизации:

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

  • Заведомо ложная ветка убрана, заведомо истинная – оставлена.

    То же самое будет с условиями в других конструкциях, например превратится в .

  • Код после удалён как недостижимый.

Переписывание синтаксических конструкций

До оптимизации:

После оптимизации:

  • Конструкция переписана в .
  • Конструкция переписана в .
  • Конструкция была переписана в .
Инлайнинг функций

Инлайнинг функции – приём оптимизации, при котором функция заменяется на своё тело.

До оптимизации:

После оптимизации (переводы строк также будут убраны):

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

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

До оптимизации:

После оптимизации:

  • Переменная заменена на , после чего стало возможным убрать.

  • Переменная заменена на строку.

    Казалось бы – зачем менять на строку? Ведь код стал ощутимо длиннее!

    …Но всё дело в том, что минификатор знает, что дальше код будет сжиматься при помощи gzip. Во всяком случае, все правильно настроенные сервера так делают.

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

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

Плюс такого подхода станет очевиден, если сжать gzip оба кода – до и после минификации. Минифицированный gzip-сжатый код в итоге даст меньший размер.

Разные мелкие оптимизации
Кроме основных оптимизаций, описанных выше, есть ещё много мелких:

Убираются лишние кавычки у ключей

Упрощаются простые вызовы Array/Object

…И ещё некоторые другие мелкие изменения кода…

Аналогия из жизни

Мы легко поймём концепцию «переменной», если представим её в виде «коробки» для данных с уникальным названием на ней.

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

Мы можем положить любое значение в коробку.

Мы также можем изменить его столько раз, сколько захотим:

При изменении значения старые данные удаляются из переменной:

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

Функциональные языки программирования

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

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

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

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

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

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

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

Функции, начинающиеся с…

  • – возвращают значение,
  • – что-то вычисляют,
  • – что-то создают,
  • – что-то проверяют и возвращают логическое значение, и т.д.

Примеры таких имён:

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

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

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

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

Несколько примеров, которые нарушают это правило:

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

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

Сверхкороткие имена функций

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

Например, во фреймворке jQuery есть функция с именем . В библиотеке Lodash основная функция представлена именем .

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

Замыкания и функции IIFE

Последнее обновление: 30.03.2018

Замыкания

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

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

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

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

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

function outer(){		// внешняя функция
	var n;				// некоторая переменная
	return inner(){		// вложенная функция
		// действия с переменной n
	}
}

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

function outer(){
    let x = 5;
    function inner(){
		x++;
		console.log(x);
	};
	return inner;
}
let fn = outer();	// fn = inner, так как функция outer возвращает функцию inner
// вызываем внутреннюю функцию inner
fn();	// 6
fn();	// 7
fn();	// 8

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

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

let fn = outer();

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

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

fn();	// 6
fn();	// 7
fn();	// 8

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

Рассмотрим еще один пример:

function multiply(n){
	var x = n;
	return function(m){ return x * m;};
}
var fn1 = multiply(5);
var result1 = fn1(6); // 30
console.log(result1); // 30

var fn2= multiply(4);
var result2 = fn2(6); // 24
console.log(result2); // 24

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

function(m){ return x * m;};

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

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

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

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

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

var fn1 = multiply(5);

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

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

var result1 = fn1(6);

Число 6 передается для параметра m во внутреннюю функцию .

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

function multiply(n){
	var x = n;
	return function(m){ return x * m;};
}
var result = multiply(5)(6); // 30
console.log(result);

Самовызывающиеся функции

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

(function(){
	console.log("Привет мир");
}());

(function (n){
	
	var result = 1;
	for(var i=1; i

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

НазадВперед

Короткий цикл вычислений

JavaScript вычисляет несколько ИЛИ слева направо. При этом, чтобы экономить ресурсы, используется так называемый «короткий цикл вычисления».

Допустим, вычисляются несколько ИЛИ подряд: . Если первый аргумент – , то результат заведомо будет (хотя бы одно из значений – ), и остальные значения игнорируются.

Это особенно заметно, когда выражение, переданное в качестве второго аргумента, имеет сторонний эффект – например, присваивает переменную.

При запуске примера ниже присвоение не произойдёт:

…А в примере ниже первый аргумент – , так что ИЛИ попытается вычислить второй, запустив тем самым присваивание:

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

Прежде, чем мы двинемся дальше, давайте разберёмся с терминологией.

  • Операнд – то, к чему применяется оператор. Например, в умножении есть два операнда: левый операнд равен , а правый операнд равен . Иногда их называют «аргументами» вместо «операндов».

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

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

    Формально мы говорим о двух разных операторах: унарное отрицание (один операнд: меняет знак) и бинарное вычитание (два операнда: вычитает).

Рекурсивный setTimeout

Есть два способа запускать что-то регулярно.

Один из них . Другим является рекурсивный . Например:

Метод выше планирует следующий вызов прямо после окончания текущего .

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

Например, необходимо написать сервис, который отправляет запрос для получения данных на сервер каждые 5 секунд, но если сервер перегружен, то необходимо увеличить интервал запросов до 10, 20, 40 секунд…
Вот псевдокод:

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

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

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

Второй использует рекурсивный :

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

Обратили внимание?

Реальная задержка между вызовами с помощью меньше, чем указано в коде!

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

Вполне возможно, что выполнение будет дольше, чем мы ожидали, и займёт более 100 мс.

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

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

Ниже представлено изображение, показывающее процесс работы рекурсивного :

Рекурсивный гарантирует фиксированную задержку (здесь 100 мс).

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

Сборка мусора и колбэк setTimeout/setInterval

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

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

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

Функции == Комментарии

Функции должны быть короткими и делать только что-то одно. Если это что-то большое, имеет смысл разбить функцию на несколько меньших. Иногда следовать этому правилу непросто, но это определённо хорошее правило.

Небольшие функции не только облегчают тестирование и отладку – само существование таких функций выполняет роль хороших комментариев!

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

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

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

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

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

Какие задачи решаются с помощью этой функции?

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

Если параметры не указывать, то function возвращает пустой jQuery-объект.

Для примера рассмотрим функцию jQuery(html,attributes) и функцию jQuery(html).

Придумывайте правильные имена

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

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

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

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

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

Несколько хороших правил:

  • Используйте легко читаемые имена, такие как или .
  • Избегайте использования аббревиатур или коротких имён, таких как , , , за исключением тех случаев, когда вы точно знаете, что так нужно.
  • Делайте имена максимально описательными и лаконичными. Примеры плохих имён: и . Такие имена ничего не говорят. Их можно использовать только в том случае, если из контекста кода очевидно, какие данные хранит переменная.
  • Договоритесь с вашей командой об используемых терминах. Если посетитель сайта называется «user», тогда мы должны называть связанные с ним переменные или , а не, к примеру, или .

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

Повторно использовать или создавать новую переменную?

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

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

Такие программисты немного экономят на объявлении переменных, но теряют в десять раз больше при отладке.

Дополнительная переменная – это добро, а не зло.

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

Итого

События изменения данных:

Событие Описание Особенности
Изменение значения любого элемента формы. Для текстовых элементов срабатывает при потере фокуса. В IE8- на чекбоксах ждёт потери фокуса, поэтому для мгновенной реакции ставят также -обработчик или .
Событие срабатывает только на текстовых элементах. Оно не ждёт потери фокуса, в отличие от . В IE8- не поддерживается, в IE9 не работает при удалении символов.
Только для IE10-. Универсальное событие для отслеживания изменения свойств элементов. Имя изменённого свойства содержится в . Используют для мгновенной реакции на изменение значения в старых IE. В IE9 не срабатывает при удалении символов.
Срабатывают при вставке/копировании/удалении текста. Если в их обработчиках отменить действие браузера, то вставки/копирования/удаления не произойдёт. Вставляемое значение получить нельзя: на момент срабатывания события в элементе всё ещё старое значение, а новое недоступно.

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

Итого

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

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

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

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

Именование функций:

  • Имя функции должно понятно и чётко отражать, что она делает. Увидев её вызов в коде, вы должны тут же понимать, что она делает, и что возвращает.
  • Функция – это действие, поэтому её имя обычно является глаголом.
  • Есть много общепринятых префиксов, таких как: , , , и т.д. Пользуйтесь ими как подсказками, поясняющими, что делает функция.

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

Ссылка на основную публикацию