Javascript полезные функции часть iv


Содержание

Функции

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

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

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

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

Определение функций

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

Идентификатор, определяющий имя функции

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

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

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

Пара фигурных скобок с нулем или более инструкций JavaScript внутри

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

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

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

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

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

Большинство функций в примере вычисляют некоторое значение, и в них инструкция return используется для возврата этого значения вызывающей программе. Функция printprops() несколько отличается в этом смысле: ее работа заключается в том, чтобы вывести имена свойств объекта. Ей не нужно возвращать какое-либо значение, поэтому в функции отсутствует инструкция return. Функция printprops() всегда будет возвращать значение undefined. (Функции, не имеющие возвращаемого значения, иногда называются процедурами.)

Вызов функций

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

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

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

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

Метод — это не что иное, как функция, которая хранится в виде свойства объекта. Если имеется функция func и объект obj, то можно определить метод объекта obj с именем method, как показано ниже:

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

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

Методы и ключевое слово this занимают центральное место в парадигме объектно-ориентированного программирования. Любая функция, используемая как метод, фактически получает неявный аргумент — объект, относительно которого она была вызвана. Как правило, методы выполняют некоторые действия с объектом, и синтаксис вызова метода наглядно отражает тот факт, что функция оперирует объектом.

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

Аргументы и параметры функций

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

Необязательные аргументы

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

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

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

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

Предположим, что была определена функция func, которая требует один аргумент x. Если вызвать эту функцию с двумя аргументами, то первый будет доступен внутри функции по имени параметра x или как arguments[0]. Второй аргумент будет доступен только как arguments[1]. Кроме того, подобно настоящим массивам, arguments имеет свойство length, определяющее количество содержащихся элементов. То есть в теле функции func, вызываемой с двумя аргументами, arguments.length имеет значение 2.

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

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

Объект Arguments иллюстрирует важную возможность JavaScript-функций: они могут быть написаны таким образом, чтобы работать с любым количеством аргументов. Следующая функция принимает любое число аргументов и возвращает значение самого большого из них (аналогично ведет себя встроенная функция Math.max()):

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

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

Не следует забывать, что arguments фактически не является массивом — это объект Arguments. В каждом объекте Arguments имеются пронумерованные элементы массива и свойство length, но с технической точки зрения это не массив. Лучше рассматривать его как объект, имеющий некоторые пронумерованные свойства.

Помимо элементов своего массива объект Arguments определяет свойства callee и caller. При попытке изменить значения этих свойств в строгом режиме ECMAScript 5 гарантированно возбуждается исключение TypeError. Однако в нестрогом режиме стандарт ECMAScript утверждает, что свойство callee ссылается на выполняемую в данный момент функцию. Свойство caller не является стандартным, но оно присутствует во многих реализациях и ссылается на функцию, вызвавшую текущую.

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

Свойства и методы функций

Мы видели, что в JavaScript-программах функции могут использоваться как значения. Оператор typeof возвращает для функций строку «function», однако в действительности функции в языке JavaScript — это особого рода объекты. А раз функции являются объектами, то они имеют свойства и методы, как любые другие объекты. Существует даже конструктор Function(), который создает новые объекты функций. В следующих подразделах описываются свойства и методы функций.

Свойство length

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

В следующем фрагменте определяется функция с именем check(), получающая массив аргументов arguments от другой функции. Она сравнивает свойство arguments.length (число фактически переданных аргументов) со свойством arguments.callee.length (число ожидаемых аргументов), чтобы определить, передано ли функции столько аргументов, сколько она ожидает. Если значения не совпадают, генерируется исключение. За функцией check() следует тестовая функция func(), демонстрирующая порядок использования функции check():

Свойство prototype

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

Прототипы и свойство prototype обсуждались в предыдущей статье.

Методы call() и apply()

Методы call() и apply() позволяют выполнять косвенный вызов функции, как если бы она была методом некоторого другого объекта. Первым аргументом обоим методам, call() и apply(), передается объект, относительно которого вызывается функция; этот аргумент определяет контекст вызова и становится значением ключевого слова this в теле функции. Чтобы вызвать функцию func() (без аргументов) как метод объекта obj, можно использовать любым из методов, call() или apply():

Любой из этих способов вызова эквивалентен следующему фрагменту (где предполагается, что объект obj не имеет свойства с именем m):

В строгом режиме ECMAScript 5 первый аргумент методов call() и apply() становится значением this, даже если это простое значение, null или undefined. В ECMAScript 3 и в нестрогом режиме значения null и undefined замещаются глобальным объектом, а простое значение — соответствующим объектом-оберткой.

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

В следующем примере демонстрируется практическое применение метода call():

Метод bind()

Метод bind() впервые появился в ECMAScript 5, но его легко имитировать в ECMAScript 3. Как следует из его имени, основное назначение метода bind() состоит в том, чтобы связать (bind) функцию с объектом. Если вызвать метод bind() функции func и передать ему объект obj, он вернет новую функцию. Вызов новой функции (как обычной функции) выполнит вызов оригинальной функции func как метода объекта obj. Любые аргументы, переданные новой функции, будут переданы оригинальной функции. Например:

Такой способ связывания легко реализовать в ECMAScript 3, как показано ниже:

Метод bind() в ECMAScript 5 не просто связывает функцию с объектом. Он также выполняет частичное применение: помимо значения this связаны будут все аргументы, переданные методу bind() после первого его аргумента. Частичное применение — распространенный прием в функциональном программировании и иногда называется каррингом (currying).

Javascript: полезные функции часть iv

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

Как разместить свой сайт на хостинге? Правильно выбранный хороший хостинг — это будущее Ваших сайтов

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

Разработка веб-сайтов с помощью онлайн платформы Wrike

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

20 ресурсов для прототипирования

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

Топ 10 бесплатных хостингов

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

Быстрая заметка: массовый UPDATE в MySQL

Ни для кого не секрет как в MySQL реализовать массовый INSERT, а вот с UPDATE-ом могут возникнуть сложности. Чтобы не прибегать к манипуляциям события ON_DUPLICATE можно воспользоваться специальной конструкцией CASE … WHEN … THEN.

Распознавание текста из изображений через командную строку

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

HTTPie — удобный инструмент похожий на cURL

cURL — это самый известный инструмент для отправки HTTP запросов из командной строки. В этом уроке мы познакомим вас с более удобным аналогом, который называется HTTPie.

Функции в JavaScript

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

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

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

Записываются функции в общем виде следующем виде:

К именам функций существуют те же требования, что и к именам переменных. Важно помнить, что функция — это особый вид переменных в JavaScript, поэтому задавать одинаковые имена для функции и для переменной НЕЛЬЗЯ.

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

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

Обязательны и круглые скобки после имени функции. Они могут оставаться пустыми, а могут содержать аргументы функции. Например, функция выводит нам приветствие в диалоговом окне alert():

Вызов функции без аргументов

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

Что можно записывать в функциях JavaScript

Функции в своем коде могут иметь различные конструкции, характерные для языка JavaScript:

  • объявление переменных ( var, let, const );
  • арифметические операции (сложение, вычитание и т.д.);
  • условные конструкции — if. else , switch. case , тернарный оператор;
  • любые виды циклов — for() , while() , do. while() , for. in ;
  • вызов других функций.

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

table += »

Ячейка » + ( j + 1 ) + «

» ;

А следующая функция будет проверять четность/нечетность числа, введенного пользователем:

Проверить четность числа

В функции использована условная конструкция if. else и тернарный оператор.

Оператор return

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

С помощью return можно возвращать логические значения ( true или false ), результат вычислений (число), строку или даже объект. Следует понимать 2 особенности, связанные с этим оператором:

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

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

Посчитать сумму чисел

Рассмотрим пример посложнее. Нам необходимо создать объект на html-странице, причем не один, а несколько (в примере будет 2 — div и абзац). Выполняться это будет в функции. Затем в основном коде для каждого из элементов задается класс, описанный в стилях.

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

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

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

Посчитать сумму чисел с проверкой

Здесь оператор «+» преобразует строку в число, если строка вида «12», «-14» и т.д. В случае строки «abcd12» происходит преобразование в тип NaN (Not a Number) и вычисление суммы не выполняется. Выводится сообщение об ошибке и возвращается 0 (ноль). Обратите внимание, что после оператора return выполнение функции прекращается.

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

Еще немного про аргументы функций в Javascript

В Javascript существует псевдомассив аргументов функции, который так и называется — arguments. И, если точное количество аргументов неизвестно, то можно воспользоваться этим массивом. Он имеет свойство length, как и обычные массивы, но методы массивов push() , pop() и т.д. вы к нему применить не сможете.

Рассмотрим использование этого массива на примере функции суммы:

Сумма чисел » + summa ( 2 , 3 , 56 , 17 , 34 , 67 ) + «

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

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

table += »

Ячейка » + ( j + 1 ) + «

» ;

В первой строчке сценария функции мы проверяем, а существует ли значение для переменной row, и если она равна undefined, т.е. значения нет, то присваиваем ей значение 2. Во второй строке можно присвоить переменной cols одно из значений — либо переданное в функцию, либо, если параметр не был передан, т.е. он равен undefined, мы назначаем опять-таки значение 2.

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

table += »

Ячейка » + ( j + 1 ) + «

» ;

Типы функций в Javascript

Все функции, которые мы рассматривали до сих пор, относятся к категории Function Declaration, т.е. функции объявленной. Кроме того, существует тип функций Function Expression, т.е. функции-выражения. Посмотрите на разницу между их объявлением:

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

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

Declaration vs Expression

Для того чтобы увидеть ошибку, нужно открыть консоль браузера (F12 и Esc).

Так вот в этом простом примере мы не увидели второго окна alert() , т.к. функция func_expression() была вызвана ДО ее объявления. И это вызвало ошибку интерпретатора, т.к. Function expression НЕ вычисляется до выполнения javascript, из-за того, что является операцией присваивания переменной. Поэтому вызов function expression нельзя осуществлять до объявления самой функции, так как переменная на тот момент содержит undefined . Именно поэтому хорошим стилем кода на JavaScript является объявление всех функций в верхней части скрипта.

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

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

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

В примере ниже глобальная переменная a перезаписывается внутри функции func() , а затем и во внутренней функции innerFunc() . А это далеко не всегда приводит к нужным результатам в процессе выполнения кода.

JavaScript функции

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

Функции состоят из набора команд и обычно выполняют какую-то одну определенную задачу (например суммирование чисел, вычисление корня и т.д.).

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

Объявление функций

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

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

Обратите внимание: даже если в функцию не передаются переменные не забывайте вставлять круглые скобки «()» после имени функции.

Обратите внимание: имена функций в JavaScript чувствительны к регистру.

Пример JavaScript функции

Функция messageWrite() в примере ниже будет выполнена только после нажатия на кнопку.

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

Передача функциям переменных

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

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

Чтобы обращаться к глобальной переменной из функции, а не ее копии используйте window.имя_переменной.

Команда return

С помощью команды return Вы можете возвращать из функций значения.

Встроенные функции

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

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

Обратите внимание: полный список встроенных функций JavaScript Вы можете найти в нашем JavaScript Справочнике.

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

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

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

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

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

Глобальные переменные уничтожаются только после закрытия страницы.

Обратите внимание: при выводе на экран переменная var2 будет иметь пустое значение, так как func1 оперирует с локальной «версией» переменной var2.

Использование анонимных функций

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

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

Четыре полезных JavaScript оператора, о которых вы могли не знать

Не секрет, что в JavaScript, операторы, предоставляют нам огромные возможности для реализации различных видов и типов логики в коде. Каждый оператор в JavaScript имеет свое назначение и синтаксис. Среди самых распространенных операторов можно выделить: условные операторы, операторы итерации и т.д. В этом посте я рассмотрю 4 не очень известных JavaScript оператора, ранее о которых вы могли и не знать, однако они помогут расширить ваши познания в JavaScript и взглянуть на ваш JS код по новому…

Пустой оператор

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

Давайте теперь для наглядности рассмотрим пару примеров. Допустим у нас есть переменная cart со значением по умолчанию «пусто» и обычная переменная goods , которая дальше по коду будет менять переменную cart в зависимости от условия goods и тогда переменная примет значение – «мало» либо «много» при условии goods > 7 в противном случае мы сгенерируем ошибку. Пример кода:

Однако код выше выдаст ошибку если значение переменной goods будет равно 7, а значение переменной cart так и останется — «пусто». Так быть естественно не должно, поэтому добавим в код пустой оператор ; и возьмем его в условие goods === 7 . После этого получится следующий код:

Теперь если goods === 7 , интерпретатор не выполнит никаких инструкций и переменная cart сохранит свое значение по умолчанию.

Также например пустой оператор можно использовать при заполнении массива с помощью цикла.

Код выше выглядит слегка необычно, и все из-за того, что у цикла отсутствуют фигурные скобки и вместо них написан пустой оператор, который как раз и отвечает за безошибочное выполнение кода и правильное зацикливание. Обратите внимание также на интересную запись cart[i++] = i , которая выполняется для каждой итерации цикла в рамках условия и массив каждый раз получает экземпляр со значениями i .

Оператор отладки (debugger)

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

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

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

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

Вступление

Авторы

Это руководство является результатом работы двух заядлых пользователей Stack Overflow: Иво Ветцель /Ivo Wetzel/ (автора текста) и Чжан И Цзян /Zhang Yi Jiang/ (дизайнера).

Участники

Переводчики

Лицензия

JavaScript Гарден распространяется под лицензией MIT и располагается на GitHub. Если вы найдёте ошибку или опечатку, пожалуйста сообщите нам о ней или запросите права на загрузку в репозиторий. Кроме того, вы можете найти нас в комнате JavaScript среди чатов Stack Overflow.

Объекты

Объекты и их свойства

В JavaScript всё ведет себя, как объект, лишь за двумя исключениями — null и undefined .

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

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

Объекты как тип данных

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

Используя объектный литерал — нотацию <> — можно создать простой объект. Новый объект наследуется от Object.prototype и не имеет собственных свойств.

Доступ к свойствам

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

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

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

Единственный способ удалить свойство у объекта — использовать оператор delete ; устанавливая свойство в undefined или null , вы только заменяете связанное с ним значение, но не удаляете ключ.

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

Приведённый код выведет две строки: bar undefined и foo null — на самом деле удалено было только свойство baz и посему только оно будет отсутствовать в выводе.

Запись ключей

Свойства объектов могут записываться как явно символами, так и в виде закавыченных строк. В связи с другим упущением в парсере JavaScript, этот код выбросит SyntaxError во всех версиях ранее ECMAScript 5.

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

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

Великий Прототип

В JavaScript отсутствует классическая модель наследования — вместо неё используется прототипная модель.

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

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

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

Замечание: В результате выполнения конструкции Bar.prototype = Foo.prototype оба объекта будут делить друг с другом один и тот же прототип. Так что изменение прототипа одного из объектов повлечёт за собой изменение прототипа другого и наоборот — вряд ли это окажется тем, чего вы ожидали.

В приведённом коде объект test наследует оба прототипа: Bar.prototype и Foo.prototype ; следовательно, он имеет доступ к функции method которую мы определили в прототипе Foo . Также у него есть доступ к свойству value одного уникального экземпляра Foo , который является его прототипом. Важно заметить, что код new Bar() не создаёт новый экземпляр Foo , а повторно вызывает функцию, которая была назначена его прототипом: таким образом все новые экземпляры Bar будут иметь одинаковое свойство value .

Замечание: Никогда не используйте конструкцию Bar.prototype = Foo , поскольку ссылка будет указывать не на прототип Foo , а на объект функции Foo . Из-за этого цепочка прототипов будет проходить через Function.prototype , а не через Foo.prototype и в результате функция method не будет содержаться в цепочке прототипов.

Поиск свойств

При обращении к какому-либо свойству объекта, JavaScript проходит вверх по цепочке прототипов этого объекта, пока не найдет свойство c запрашиваемым именем.

Если он достигнет верхушки этой цепочки ( Object.prototype ) и при этом так и не найдёт указанное свойство, вместо него вернётся значение undefined.

Свойство prototype

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

При этом присвоение объектов, как в примере выше, позволит вам динамически создавать цепочки прототипов.

Производительность

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

Вдобавок, при циклическом переборе свойств объекта, будет обработано каждое свойство, существующее в цепочке прототипов.

Расширение встроенных прототипов

Часто встречается неверное применение прототипов — расширение прототипа Object.prototype или прототипов одного из встроенных объектов JavaScript.

Подобная практика нарушает принцип инкапсуляции и имеет соответствующее название — monkey patching. К сожалению, в основу многих широко распространенных фреймворков, например Prototype, положен принцип изменения базовых прототипов. Вам же стоит запомнить — от хорошей жизни прототипы встроенных объектов не меняют.

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

Заключение

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

Функция hasOwnProperty

Если вам необходимо проверить, определено ли свойство у самого объекта, а не в его цепочке прототипов, вы можете использовать метод hasOwnProperty , который все объекты наследуют от Object.prototype .

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

hasOwnProperty — единственная функция в JavaScript, которая позволяет получить свойства объекта без обращения к цепочке его прототипов.

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

hasOwnProperty как свойство

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

Заключение

Единственным способом проверить существование свойства у объекта является использование метода hasOwnProperty . При этом рекомендуется использовать этот метод в каждом цикле for in вашего проекта, чтобы избежать возможных ошибок с ошибочным заимствованием свойств из прототипов родительских объектов. Также вы можете использовать конструкцию <>.hasOwnProperty.call(. ) на случай, если кто-то вздумает расширить прототипы встроенных объектов.

Цикл for in

Как и оператор in , цикл for in проходит по всей цепочке прототипов, обходя свойства объекта.

Примечание: Цикл for in не обходит те свойства объекта, у которых атрибут enumerable установлен в false ; как пример — свойство length у массивов

Так как изменить поведение цикла for in как такового не представляется возможным, то для фильтрации нежелательных свойств объекта внутри этого цикла используют метод hasOwnProperty из Object.prototype .

Примечание: Цикл for in всегда обходит всю цепочку прототипов полностью: таким образом, чем больше прототипов (слоёв наследования) в цепочке, тем медленнее работает цикл.

Использование hasOwnProperty в качестве фильтра

Это единственная версия правильного использования цикла. Благодаря использованию hasOwnProperty будет выведено только свойство moo . Если же убрать hasOwnProperty , код становится нестабилен и могут возникнуть ошибки, особенно если кто-то изменил встроенные прототипы, такие как Object.prototype .

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

Рекомендации

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

Функции

Выражения и объявление функций

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

Объявление function

В следующем примере описанная функция резервируется перед запуском всего скрипта; за счёт этого она доступна в любом месте кода, вне зависимости от того, где она определена — даже если функция вызывается до её фактического объявления в коде.

function как выражение

В этом примере безымянная и анонимная функция присваивается переменной foo .

Так как в данном примере выражение var — это определение функции, переменная с именем foo будет заранее зарезервирована перед запуском скрипта (таким образом, foo уже будет определена во время его работы).

Но поскольку присвоения исполняются непосредственно во время работы кода, foo по умолчанию будет присвоено значение undefined (до обработки строки с определением функции):

Выражения с именованными фунциями

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

Здесь объект bar не доступен во внешней области, так как имя bar используется только для присвоения переменной foo ; однако bar можно вызвать внутри функции. Такое поведение связано с особенностью работы JavaScript с пространствами имен — имя функции всегда доступно в локальной области видимости самой функции.

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

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

1. Глобальная область видимости

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

2. Вызов функции

Тут this также ссылается на глобальный объект.

ES5 Замечание: В strict-режиме теряется понятие глобальности, поэтому в этом случае this будет иметь значение undefined .

3. Вызов метода

В данном примере this ссылается на test .

4. Вызов конструктора

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

5. Переопределение this

Когда мы используем методы call или apply из Function.prototype , то внутри вызываемой функции this явным образом будет присвоено значение первого передаваемого параметра.

Исходя из этого, в предыдущем примере (строка с apply ) правило #3 вызов метода не будет применено, и this внутри foo будет присвоено bar .

Замечание: this нельзя использовать внутри литералов <> ( Object ) для ссылки на сам объект. Т.е. если мы напишем var obj = , то me не будет ссылаться на obj , поскольку this присваивается только по одному из пяти описанных правил.

Наиболее распространенные ошибки

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

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

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

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

Замечание от перев. Кроме that также часто встречаются this_ , self_ и другие варианты, но лучше принять для себя that как стандарт и тогда, возможно, все вокруг тоже будут им пользоваться.

Назначение методов

Еще одной фичей, которая не работает в JavaScript , является создание псевдонимов для методов, т.е. присвоение метода объекта переменной.

Следуя первому правилу test вызывается как обычная функция; следовательно this внутри него больше не ссылается на someObject .

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

В момент, когда будет вызван method нового экземпляра Bar , this будет ссылаться на этот самый экземпляр.

Замыкания и ссылки

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

Эмуляция приватных свойств

В данном примере Counter возвращает два замыкания: функции increment и get . Обе эти функции сохраняют ссылку на область видимости Counter и, соответственно, имеют доступ к переменной count из этой самой области.

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

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

В приведенном примере мы не изменяем переменную count в области видимости Counter , т.к. foo.hack не объявлен в данной области. Вместо этого будет создана или перезаписана глобальная переменная count ;

Замыкания внутри циклов

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

Данный код не будет выводить числа с 0 до 9 , вместо этого число 10 будет выведено десять раз.

Анонимная функция сохраняет ссылку на i и, когда будет вызвана функция console.log , цикл for уже закончит свою работу, а в i будет содержаться 10 .

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

Во избежание ошибок

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

Анонимная функция-обертка будет вызвана сразу же, и в качестве первого аргумента получит i , значение которой будет скопировано в параметр e .

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

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

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

Объект arguments

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

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

Объект arguments не является наследником Array . Он, конечно же, очень похож на массив и даже содержит свойство length — но он не наследует Array.prototype , а представляет собой Object .

По этой причине, у объекта arguments отсутствуют стандартные методы массивов, такие как push , pop или slice . Хотя итерация с использованием обычного цикла for по аргументам работает вполне корректно, вам придётся конвертировать этот объект в настоящий массив типа Array , чтобы применять к нему стандартные методы массивов.

Конвертация в массив

Указанный код вернёт новый массив типа Array , содержащий все элементы объекта arguments .

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

Передача аргументов

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

Другой трюк — использовать и call и apply вместе, чтобы быстро создать несвязанную обёртку:

Формальные аргументы и индексы аргументов

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

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

Мифы и правда о производительности

Объект arguments создаётся во всех случаях, лишь за двумя исключениями — когда он переопределён внутри функции (по имени) или когда одним из её параметров является переменная с таким именем. Неважно, используется при этом сам объект или нет.

Геттеры и сеттеры создаются всегда; так что их использование практически никак не влияет на производительность.

ES5 Замечание: Эти геттеры и сеттеры не создаются в strict-режиме.

Однако, есть один момент, который может радикально понизить производительность современных движков JavaScript. Этот момент — использование arguments.callee .

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

Крайне не рекомендуется использовать arguments.callee или какое-либо из его свойств. Никогда.

ES5 Замечание: В strict-режиме использование arguments.callee породит TypeError , поскольку его использование принято устаревшим.

Конструктор

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

Внутри конструктора (вызываемой функции) this будет указывать на новосозданный Object . Прототипом этого нового объекта будет prototype функции, которая была вызвана в качестве конструктора.

Если вызываемая функция не имеет явного возврата посредством return , то вернётся this — этот новый объект.

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

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

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

Этот пример в некоторых случаях всё-таки может сработать: это связано с поведением this в JavaScript — он будет восприниматься парсером как глобальный объект.

Фабрики

Если хотите избавится от необходимости использования new , напишите конструктор, возвращающий значение посредством return .

В обоих случаях при вызове Bar мы получим один и тот же результат — новый объект со свойством method (спасибо замыканию за это).

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

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

Создание объектов с использованием фабрик

Часто рекомендуют не использовать new , поскольку если вы его забудете, это может привести к ошибкам.

Чтобы создать новый объект, лучше использовать фабрику и создать новый объект внутри этой фабрики.

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

  1. Он использует больше памяти, поскольку созданные объекты не хранят методы в прототипе и соответственно для каждого нового объекта создаётся копия каждого метода.
  2. Чтобы эмулировать наследование, фабрике нужно скопировать все методы из другого объекта или установить прототипом нового объекта старый.
  3. Разрыв цепочки прототипов просто по причине забытого ключевого слова new идёт в разрез с духом языка.

Заключение

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

Области видимости и пространства имён

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

Замечание: Нотация <. >будет интерпретирована как блочное выражение, а не как литерал объекта, если она не используется в присваивании, операторе return или в качестве функции. Это замечание, вкупе с автоматической расстановкой точек с запятой, может привести к чрезвычайно хитрым ошибкам.

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

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

Проклятие глобальных переменных

Вышеприведённые два скрипта не приводят к одному результату. Скрипт A определяет переменную по имени foo в глобальной области видимости, а скрипт B определяет foo в текущей области видимости.

Повторимся, это вообще не тот же самый эффект. Если вы не используете var — то вы в большой опасности.

Из-за того что оператор var опущен внутри функции, фунция test перезапишет значение foo . Это поначалу может показаться не такой уж и большой проблемой, но если у вас имеется тысяча строк JavaScript-кода и вы не используете var , то вам на пути встретятся страшные и трудноотлаживаемые ошибки — и это не шутка.

Внешний цикл прекратит работу сразу после первого вызова subLoop , поскольку subLoop перезаписывает глобальное значение переменной i . Использование var во втором цикле for могло бы вас легко избавить от этой ошибки. Никогда не забывайте использовать var , если только влияние на внешнюю область видимости не является тем, что вы намерены получить.

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

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

В то время как foo и i — локальные переменные в области видимости функции test , присвоение bar переопределит значение одноимённой глобальной переменной.

Высасывание

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

Этот код трансформируется ещё перед исполнением. JavaScript перемещает операторы var и определение function наверх ближайшей оборачивающей области видимости.

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

В исходном коде оператор if изменял глобальную переменную goo , когда, как оказалось, он изменяет локальную переменную — в результате работы высасывания.

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

Но, конечно же, этот код работает: из-за того, что оператор var был перемещён наверх глобальной области видимости

Порядок разрешения имён

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

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

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

  1. Если в текущей области видимости есть выражение var foo , использовать его.
  2. Если один из параметров функции называется foo , использовать его.
  3. Если функция сама называется foo , использовать её.
  4. Перейти на одну область видимости выше и начать с п. 1

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

Пространства имён

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

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

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

Заключение

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

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

Массивы

Итерации по массивам и свойства

Несмотря на то, что массивы в JavaScript являются объектами, нет достаточных оснований для использования цикла for in для итерации по элементам массива. Фактически, существует несколько весомых причин против использования for in в массивах.

Замечание: Массивы в JavaScript не являются ассоциативными массивами. Для связывания ключей и значений в JavaScript есть только объекты. И при том, что ассоциативные массивы сохраняют заданный порядок, объекты не делают этого.

Во время выполнения for in циклически перебираются все свойства объекта, находящиеся в цепочке прототипов. Единственный способ исключить ненужные свойства — использовать hasOwnProperty , а это в 20 раз медленнее обычного цикла for .

Итерирование

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

В примере выше есть один дополнительный приём, с помощью которого кэшируется величина длины массива: l = list.length .

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

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

Свойство length

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

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

Заключение

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

Конструктор Array

Так как в конструкторе Array есть некоторая двусмысленность, касающаяся его параметров, настоятельно рекомендуется при создании массивов всегда использовать синтаксис литеральной нотации — [] .

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

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

Заключение

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

Равенство и сравнение

JavaScript имеет 2 различных способа сравнения значений объектов на равенство.

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

Оператор сравнения состоит из двух символов равенства: ==

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

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

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

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

Оператор строгого равенства состоит из трёх символов равенства: ===

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

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

Сравнение объектов

Хотя оба оператора == и === заявлены как операторы равенства, они ведут себя по-разному, когда хотя бы один из операндов является Object .

Здесь оба операнда сравниваются на идентичность, а не на равенство; то есть будет проверяться, являются ли операнды одним экземпляром объекта, так же как делает is в Python и сравниваются указатели в С.

Заключение

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

Оператор typeof

Оператор typeof (вместе с instanceof ) — это, вероятно, самая большая недоделка в JavaScript, поскольку, похоже, он поломан более, чем полностью.

Хотя instanceof еще имеет ограниченное применение, typeof на самом деле имеет только один практический случай применения, который при всём при этом не является проверкой типа объекта.

Замечание: Хотя для вызова typeof также можно использовать синтаксис функции, т.е. typeof(obj) , на самом деле это не функция. Двойные круглые скобки будут работать нормально и возвращаемое значение будет использоваться как операнд оператора typeof . Но функции typeof — не существует.

Таблица типов JavaScript

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

Класс представляет собой значение внутреннего свойства [[Class]] объекта.

Из спецификации: Значением [[Class]] может быть одна из следующих строк: Arguments , Array , Boolean , Date , Error , Function , JSON , Math , Number , Object , RegExp , String .

Для того, чтобы получить значение [[Class]] , необходимо вызвать метод toString у Object.prototype .

Класс объекта

Спецификация предоставляет только один способ доступа к значению [[Class]] — используя Object.prototype.toString .

В примере выше Object.prototype.toString вызывается со значением this, являющимся объектом, значение [[Class]] которого нужно получить.

ES5 Замечание: Для удобства в ECMAScript 5 возвращаемое значение Object.prototype.toString для null и undefined было изменено с Object на Null и Undefined соответственно.

Проверка переменных на определённость

Выше проверяется, было ли foo действительно объявлено или нет; просто обращение к переменной приведёт к ReferenceError . Это единственное, чем на самом деле полезен typeof .

Заключение

Для проверки типа объекта настоятельно рекомендуется использовать Object.prototype.toString — это единственный надежный способ. Как показано выше в таблице типов, некоторые возвращаемые typeof значения не определены в спецификации: таким образом, они могут отличаться в различных реализациях.

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

Оператор instanceof

Оператор instanceof сравнивает конструкторы двух операндов. Это полезно только когда сравниваются пользовательские объекты. Использование на встроенных типах почти так же бесполезно, как и оператор typeof.

Сравнение пользовательских объектов

Использование instanceof со встроенными типами

Здесь надо отметить одну важную вещь: instanceof не работает на объектах, которые происходят из разных контекстов JavaScript (например, из различных документов в web-браузере), так как их конструкторы и правда не будут конструкторами тех самых объектов.

Заключение

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

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

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

ES5 Замечание: Числовые литералы, которые начинаются с 0, интерпретируются как восьмеричные (Base 8). В ECMAScript 5 strict mode удалена поддержка восьмеричной системы.

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

Конструкторы встроенных типов

Конструкторы встроенных типов, например, Number и String ведут себя различным образом, в зависимости от того, вызываются они с ключевым словом new или без.

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

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

Лучший вариант — это явное приведение к одному из трех возможных типов.

Приведение к строке

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

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

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

Приведение к булеву типу

Используя оператор not ( ! ) дважды, значение может быть приведено к логическому (булеву) типу.

Нативности

Почему нельзя использовать eval

Функция eval выполняет строку кода JavaScript в локальной области видимости.

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

Любой ценой избегайте использования функции eval . 99.9% случаев её «использования» могут достигаться без её участия.

eval под прикрытием

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

Проблемы с безопасностью

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

Заключение

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

undefined и null

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

Тип undefined

undefined — это тип с единственным возможным значением: undefined .

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

ES5 Замечание: в ECMAScript 5 переменная undefined больше не доступна на запись в strict-режиме, однако она всё так же может быть перегружена по имени, например — функцией с именем undefined .

Несколько случаев, когда возвращается undefined :

  • При попытке доступа к глобальной переменной undefined (если она не изменена).
  • Неявный возврат из функции при отсутствии в ней оператора return .
  • Из операторов return , которые ничего не возвращают.
  • В результате поиска несуществующего свойства у объекта (и доступа к нему).
  • Параметры, которые не были переданы в функцию явно.
  • При доступе ко всему, чьим значением является undefined .

Обработка изменений значения undefined

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

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

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

Другой способ достичь того же эффекта — использовать определение внутри обёртки.

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

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

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

Он используется во внутренних механизмах JavaScript (например для определения конца цепочки прототипов за счёт присваивания Foo.prototype = null ). Но в большинстве случаев тип null может быть заменён на undefined .

Автоматическая вставка точек с запятой

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

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

Происходит вставка и парсер пытается снова.

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

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

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

Ниже представлен результат игры парсера в «угадалки».

Замечание: Парсер JavaScript некорректно обрабатывает оператор return , за которым следует новая строка; кстати, причина может быть и не в автоматической вставке точек с запятой, но это в любом случае нежелательный побочный эффект

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

«Висящие» скобки

Если парсер встречает «висящую» скобку, то он не вставляет точку с запятой.

Такой код трансформируется в строку

Чрезвычайно высоки шансы, что log возвращает не функцию; таким образом, эта строка вызовет TypeError с сообщением о том, что undefined не является функцией .

Заключение

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

Другое

setTimeout и setInterval

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

Замечание: Таймауты не являются частью стандарта ECMAScript, они были разработаны как раздел спецификации DOM.

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

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

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

Замечание: Поскольку setTimeout принимает объект функции в качестве первого параметра, часто совершается ошибка в использовании setTimeout(foo(), 1000) , при котором будет использоваться возвращённое значение от вызова функции foo , а не вызываться сама функция foo . В большинстве случаев ошибка пройдёт незамеченной, а в случае если функция возвращает undefined , setTimeout вообще не породит никакой ошибки.

Поочерёдные вызовы с использованием setInterval

setTimeout вызывает функцию единожды; setInterval — как и предполагает название — вызывает функцию каждые X миллисекунд. И его использование не рекомендуется.

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

В приведённом коде foo выполнится один раз и заблокирует этим главный поток на одну секунду.

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

Разбираемся с потенциальной блокировкой кода

Самый простой и контролируемый способ — использовать setTimeout внутри самой функции.

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

Очистка таймаутов вручную

Удаление таймаутов и интервалов работает через передачу соответствующего идентификатора либо в функцию clearTimeout , либо в функцию clearInterval — в зависимости от того, какая функция set. использовалась для его получения.

Очистка всех таймаутов

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

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

Скрытое использование eval

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

Замечание: Поскольку функции работы с таймаутами не определены в стандарте ECMAScript, точная внутренняя механика их работы может различаться от движка к движку. Известно, что Microsoft JScript использует конструктор Function вместо eval .

Поскольку eval в этом случае не вызывается напрямую, переданная в setTimeout строка будет выполнена в глобальной области видимости; так что локальная переменная foo из области видимости bar не будет выполнена.

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

Замечание: При том, что синтаксис setTimeout(foo, 1000, 1, 2, 3) разрешено использовать, это крайне не рекомендуется, поскольку может привести к сложно распознаваемым ошибкам при работе с методами.

Заключение

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

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

Пояснения

От переводчиков

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

К примеру, в статье про сравнение объектов авторы настоятельно рекомендуют использовать только оператор строгого неравенства === . Но мы считаем, что если вы уверены и осознали, что оба сравниваемых операнда имеют один тип, вы имеете право опустить последний символ = . Вы вольны применять строгое неравенство только в случаях, когда вы не уверены в типах операндов ( !== undefined — это полезный приём). Так в вашем коде будут опасные и безопасные области, но при этом по коду будет явно видно, где вы рассчитываете на переменные одинаковых типов, а где позволяете пользователю вольности.

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

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

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

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

Основы языка JavaScript

1. Основы языка JavaScript *

1.1. Основные особенности JavaScript *

1.2. Возможности языка JavaScript *

1.3. Основные типы данных *

1.4. Переменные. Приведение типов *

1.5. SCRIPT-вставки в HTML-документе *

2. Операторы, выражения, функции *

2.1. Операторы: арифметических действий, присваивания, инкрементные, декрементные. Условные выражения *

2.2. Строковые операции *

2.3. Побитовые операции присваивания *

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

2.5. Старшинство операций *

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

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

3.1. Классы, объекты, поля данных, методы *

3.2. Работа с полями данных и методами уже существующих объектов *

3.3. Задание нового класса объектов. Квалификатор this *

3.4. Операторы for и with для работы с объектами *

3.5. Правила работы с объектами *

3.6. Динамическое формирование документа *

4. Классы и объекты языка JavaScript *

4.1. Класс Global (задан неявно) *

4.3. Класс Window *

4.4. Коллекция фреймов (window.frames) *

4.5. Класс Document (window.document) *

4.6. Класс Location (window.location) *

4.7. Класс Link (document.link) *

4.8. Класс History *

4.9. Класс MimeType *

4.10. Класс Navigator *

5. Экранные формы *

5.1. Класс Form (document.forms[i]) *

5.2. Классы Button, Checkbox, Hidden, Password, Radio, Reset, Submit, Text, Textarea *

5.3. Класс Checkbox *

5.6. Классы Text и Password *

5.7. Класс Textarea *

5.8. Классы Select и Option *

6. Классы для программной обработки данных *

6.1. Класс Object *

6.1.1. Свойство constructor *

6.1.2. Свойство prototype *

6.2. Класс Number *

6.3. Класс Boolean *

6.4. Класс String *

6.6. Класс Function *

6.7. Класс JavaArray *

6.8. Класс JavaClass *

6.9. Класс JavaObject *

6.10. Класс JavaPasckage *

6.11. Класс Screen *

6.11.1. Свойства availHeight и availWidth для Netscape Navigator *

6.11.2. Свойство bufferDepth для Internet Explorer *

6.11.3. Свойство colorDepth *

6.11.4. Свойства height и width *

6.11.5. Свойство pixelDepth для Netscape Navigator *

6.11.6. Свойство updateInterval для Internet Explorer *

JavaScript — это относительно простой объектно-ориентированный язык, предназначенный для создания небольших клиентских и серверных приложений для Internet. Программы, написанные на языке JavaScript, включаются в состав HTML-документов и распространяются вместе с ними. Программы просмотра (браузеры – от англ. browser ) типа Netscape Navigator и Microsoft Internet Explorer распознают встроенные в текст документа программы-вставки ( script- коды) и выполняют их. Таким образом, JavaScript — интерпретируемый язык программирования. Примерами программ на JavaScript могут служить программы, проверяющие введенные пользователем данные или выполняющие какие-то действия при открытии или закрытии документа. Такие программы могут реагировать на действия пользователя — нажатие кнопок «мыши», ввод данных в экранной форме или перемещение «мыши» по странице. Более того, JavaScript-программы могут управлять самим браузером и атрибутами документа.

Язык JavaScript, будучи схожим по синтаксису с языком Java, за исключением объектной модели, в то же время не обладает такими свойствами, как статические типы данных и строгой типизацией. В JavaScript, в отличие от Java, понятие классов не является основой синтаксических конструкций языка. Такой основой является небольшой набор предопределенных типов данных, поддерживаемых исполняемой системой: числовые, булевские и строковые; функции, которые могут быть как самостоятельными, так и методами объектов (метод в терминологии JavaScript — не что иное, как функция/подпрограмма); объектная модель с большим набором предопределенных объектов со своими свойствами и методами, а также правилами задания в программе пользователя новых объектов.

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

С его помощью можно динамически управлять отображением и содержимым HTML-документов. Можно записывать в отображаемый на экран документ произвольный HTML-код в процессе синтаксического анализа загруженного браузером документа. С помощью объекта Document можно генерировать документы «с нуля» в зависимости от предыдущих действий пользователя или каких-либо иных факторов.

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

JavaScri pt позволяет взаимодействовать с содержимым документов. Объект Document и содержащиеся в нем объекты позволяют программам читать части HTML- документа и иногда взаимодействовать с ними. Сам текст прочитать невозможно, но можно, например, получить список гипертекстовых ссылок, имеющихся в данном документе. На текущий момент широкие возможности взаимодействия с содержимым документов обеспечивает объект Form и объекты, которые он может содержать: Button, Checkbox, Hidden, Password, Radio, Reset, Select, Submit, Text и Textarea.

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

JavaScript дает возможность выполнять произвольные математические вычисления. Кроме того, этот язык имеет развитые средства работы со значениями даты и времени. JavaScript был создан в качестве альтернативы CGI -программам и языку сценариев Perl , а также в качестве дополнения м в ряде случаев альтернативы языку Java.

Ниже приведена таблица, в которой проводится сравнение Java и JavaScript:

JavaScript

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

Исходный код программ не распространяется с приложением -апплетом. Апплеты загружаются с сервера из независимых файлов.

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

Программа компилируется в машинно-независимый байтовый код Java-код, после чего выкладыватся на сервер. Браузер (виртуальная Java-машина) исполняет Java-код.

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

Объектно-ориентированный . Программировать без использования объектного программирования нельзя. Апплеты состоят из классов с возможностью иерархического наследования по традиционной схеме наследования. Использование наследования и полиморфизма – основа программирования в Java.

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

Структура объектов полностью задается на этапе компиляции их классов.

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

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

Динамическое связывание кода с объектами : ссылки на объекты проверяются во время выполнения программы.

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

Значения переменных, функций и выражений бывают следующих типов:

в десятичной системе единиц: 0, 29, 70, -147 и т.п.;

в 16-ричной: 0х70 или 0х70, 0 X FA7D0 и т.п.;

в 8-ричной: 070, 0710 ( Внимание. В едущий ноль воспринимается как символ 8-ричного числа ) и т.п.

0.0, -2.9, 0.7E1, 14.7e-2, 1e+308 (максимальное вещественное число), 1.001e-305 (минимальное по модулю вещественное число, отличное от нуля) и т.п.;

  • логические (булевские): true и false;
  • строковые: » Привет, все! «, » ОК «, ‘ Слово «Привет!» с кавычками внутри строки’, «Другой вариант ‘Привет’ с кавычками внутри строки» и т.п. (допускаются оба типа кавычек и многократное использование таких пар внутри друг друга). Специальные символы обозначаются комбинацией символа \ и буквы (или последовательности цифр), например: \b — «забой», \n — перевод на новую строку, \» — » кавычка «.
  • null — специальное значение для обозначения “пустого множества” значений.
  • Глобальные переменные можно вводить в любом месте текста программы путем простого присваивания значения . Но необходимо, чтобы переменная была определена до того момента, когда вызывается при исполнении:

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

    myVariable=» Теперь это текстовая переменная «

    При задании переменной использование зарезервированного слова var не обязательно, но желательно, т.к. помогает при использовании отладчика фирмы Microsoft и делает текст программы более структурированным. На деле вместо переменной в текущем объекте window создается новое поле с таким именем. В функциях при задании локальных переменных использование var обязательно (иначе будет создана глобальная переменная).

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

    a=7+» раз отмерь,»+1+»раз присвой «

    будет строка «7 раз отмерь, 1 раз присвой «.

    Стоит отметить, что существуют также функции parseFloat и parseInt , которые осуществляют преобразование из строкового значения в численное.

    Идентификатором переменной может быть последовательность символов из набора букв от «A» до «Z», от «a» до «z», цифр от «0» до «9», а также символ подчеркивания «_». При этом первым символом имени не может быть цифра, а заглавные и строчные буквы отличаются (т. е. имена MyVariable и myvariable относятся к разным переменным).

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

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

    Функции в JavaScript

    Зачастую нам нужно повторять одни и те же действия в разных частях кода JavaScript. Например, иногда требуется передать сообщение при входе пользователя на сайт, при выходе и в других случаях. Чтобы не повторять тот же код множество раз, используют функции (functions). По сути, функции — это основные «строительные кирпичики» программы на JavaScript.

    Примеры встроенных функций: • prompt(message, default); • alert(message); • confirm(question).

    Однако в JavaScript можно создавать и свои функции.

    Объявление функций в JS

    Рассмотрим пример создания function для показа сообщений showMessage() :

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

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

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

    Локальные переменные функции

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

    Помните, что блоки while, switch, for, if/else, do..while никак не влияют на зону видимости переменных, то есть при объявлении переменных в данных блоках они будут видны во всей функции. Пример:

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

    Внешние переменные функции

    Функция позволяет вызвать и внешнюю переменную, например:

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

    Однако если бы мы внутри функции в строке (1) объявили свою локальную переменную var userName , все обращения задействовали бы её, то есть внешняя переменная не изменилась бы.

    Параметры, которые можно вызвать функцией

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

    Помните, что когда код будет передан, параметры скопируются в локальные переменные. Также функцию можно вызвать практически с любым количеством аргументов, а если при вызове параметр не будет передан, он считается равным undefined. К примеру, функцию отображения сообщений showMessage(from, text) можно без проблем вызвать, используя один аргумент:

    Выбор имени function

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

    Функцию, которая что-то показывает, называют show (это лучший вариант для имени):

    Запуск function, которая что-то получает, называют get, вычисляет — calc и т. д.

    Примеры, каким именем можно назвать функцию:

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

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

    Функция jQuery() в JavaScript

    Говоря о применении функций в JS, нельзя не упомянуть jQuery — известнейшую библиотеку языка программирования JavaScript, благодаря которой осуществляется взаимодействие HTML и JavaScript. Работа с ней начинается с вызова основной функции jQuery() либо $() . Данная функция (function) может выполнять разные действия, что зависит от того, какое значение передать в качестве параметров аргумента.

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

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

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

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

    Функция jQuery(html,attributes)

    Function служит для создания DOM-элемента с параметрами. Необходимый элемент указывается в первом аргументе с помощью HTML-строки. Атрибуты к нему указываются во втором аргументе с помощью объекта JavaScript (PlainObject).

    Данный способ вызова функции имеет два параметра: • html — обязательный параметр типа htmlString, содержит DOM-элемент; • attributes — необязательный параметр типа PlainObject. Это объект, содержащий атрибуты, методы и события, которые нужно передать создаваемому элементу.

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

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

    Ссылки в JS

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

    • Самый простой метод, позволяющий осуществлять вызов — вывод alert в ссылке. Пример такой ссылки (ссылку можно запустить без проблем из любого браузера):
    • Второй метод вызова ссылки имеет более сложную конструкцию. В этом случае ссылку можно сделать с помощью функции document.write(). А оформить такую ссылку можно следующим образом:
    • В качестве третьего метода продемонстрируем ещё более усложнённый вариант. Ссылка и её вызов осуществляются с помощью переменных, т. к. сама ссылка и её текст выведены в отдельные переменные:

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

    Глава 12

    Краткий курс JavaScript

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

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

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

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

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

    Далее в этой главе рассматриваются основные возможности языка JavaScript и правила написания программ с его использованием.

    Объем книги не позволяет привести развернутое описание языка программирования, поэтому материал изложен кратко.

    12.1. Замечание о строках кода JavaScript

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

    a = a + b; c = a – b / 2

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

    a = b + «=» + «Очень длинная строка текста, которая настолько длинна, что «+» даже не помещается на странице»

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

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

    12.3. Типы данных, переменные, выражения

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

    Таблица 12.1. Типы данных JavaScript

    Перечисленные выше типы данных применяются в выражениях, например следующее выражение: 524 + 45.23 + «sometext» в результате даст значение «569.23sometext». Из полученного результата можно увидеть, что при расчете значений выражений производится автоматическое преобразование типов значений от менее универсальных типов к более универсальным (сверху вниз по табл. 12.1).

    Относительно строковых значений осталось рассказать о том, что такое escape?символы. Так вот, escape?символы применяются для вставки в строки символов, которые не могут быть введены в текстовом редакторе либо являются недопустимыми (например, двойные кавычки в строке, заключенной в двойные кавычки). Доступные в JavaScript escape?символы, а также их описания приведены в табл. 12.2.

    Таблица 12.2. Escape-символы

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

    Переменные могут использоваться в выражениях наряду с численными и строковыми значениями (численными и строковыми константами). Например, если в переменной val содержится значение «text = «, то результатом выражения val + «sometext» будет строка «text = sometext».

    Регистр символов в именах переменных, а также функций, классов (на будущее) в JavaScript имеет значение. Это значит, что, например, val и Val – это различные переменные.

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

    Как видно, в одной строке можно объявить сразу несколько переменных. При объявлении переменных их можно инициализировать (оператор = используется для присвоения значений переменным). Неинициализированные переменные содержат значение undefined (в данном случае это переменная v1). Переменные могут также содержать специальное значение null, означающее, что в переменной нет данных. Кроме того, можно использовать специальное значение NaN (Not a Number), сигнализирующее о том, что в переменной содержится не число.

    Если необходимо определить тип выражения или тип значения, которое хранится в переменной, то можно использовать оператор typeof(выражение). Этот оператор возвращает строковые значения: number (для численных выражений или значения NaN), string (для строк), object (для значения null и ссылок на объекты).

    12.4. Простые и составные операторы

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

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

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

    12.5. Операторы языка JavaScript

    Арифметические операторы. Инкремент и декремент

    В языке JavaScript присутствуют стандартные для языков программирования арифметические операторы, позволяющие производить вычисления с численными и строковыми значениями (для строк только оператор +).

    К арифметическим операторам JavaScript относятся: + (сложение), – (вычитание), * (умножение), / (деление). В дополнение к ним присутствует оператор взятия остатка от деления %. Все указанные операторы являются бинарными (в том смысле, что принимают два значения и возвращают одно). Кроме указанных операторов, существует еще и унарный оператор –, инвертирующий значение аргумента (например –123, –val).

    В JavaScript предусмотрена также удобная возможность записи выражений вида i = i + 1, i = i – 1, i = i * j и пр., где i – произвольная переменная, а j – произвольное выражение. Первые два выражения сокращенно записываются как инкремент и декремент: i++ и i–. Третье выражение и подобные ему можно сократить, применив следующие операторы:

    • оператор –=, то есть i = i – j эквивалентно i –= j;

    • оператор +=, то есть i = i + j эквивалентно i += j;

    • оператор *=, то есть i = i * j эквивалентно i *= j;

    • оператор /=, то есть i = i / j эквивалентно i /= j;

    • оператор %=, то есть i = i % j эквивалентно i %= j.

    Кроме того, предусмотрены соответствующие операторы &=, ^=, |= для двоичных операторов и >=, >>>= для операторов сдвига.

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

    И логические операторы, и операторы сравнения возвращают результат – логическое значение true или false. Однако логические операторы принимают аргументы логического типа, в то время как операторы сравнения сравнивают значения произвольного типа. И логические операторы, и операторы сравнения языка JavaScript приведены в табл. 12.3.

    Таблица 12.3. Логические операторы и операторы сравнения

    Двоичные операторы

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

    Итак, двоичных операторов в JavaScript семь. Эти операторы перечислены в табл. 12.4.

    Таблица 12.4. Двоичные операторы JavaScript

    Приоритет операторов

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

    5. >, >=, 3) ? b : 3; //Значение переменной a будет не меньше 3

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

    Если значение выражения условие равно true, то выполняется оператор1 (это может быть как простой, так и составной оператор), в противном случае выполняется оператор2 (также или простой, или составной оператор). Часть else оператор2 является необязательной. Ниже приведено несколько примеров использования оператора if:

    if (b != 0) a /= b; //Проверяется отсутствие деления на ноль

    //Какие-то действия по информированию (в данном случае ничего)

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

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

    Оператор switch работает следующим образом. Сначала вычисляется значение выражения выражение. Далее это значение сравнивается с выражениями при каждом ключевом слове case сверху вниз. Если, например, значение выражение совпало со значением выражение2, то выполняется последовательность операторов операторы2. Выполнение продолжается до тех пор, пока не будет встречен оператор break либо выполнение не дойдет до конца тела оператора switch (закрывающая скобка >). Если перед следующим ключевым словом case отсутствует оператор break, то выполнится последовательность операторов операторы3 и т. д. Ключевое слово default используется для того, чтобы задать последовательность операторов, которые должны выполниться при несовпадении значения выражение со всеми выражениями при всех ключевых словах case. Для иллюстрации сказанного приводится пример использования оператора switch:

    //Операторы выполнятся при var == 1

    //Операторы выполнятся при var == 2

    //Операторы выполнятся при var == 2 или var == 3

    //Операторы выполнятся при var == 4

    //Операторы выполнятся при var != 1 && var != 2 && var != 3

    Циклы

    Язык JavaScript поддерживает три вида циклов: for, while и do-while. Начнем с более простых циклов while и do-while. Цикл while позволяет выполнять нужные действия, пока истинно выражение?условие. Формат оператора while следующий:

    Здесь условие – логическое выражение (аналогично операторам if и ?), а оператор – простой или составной оператор, выполняемый при каждой итерации цикла. Пример использования цикла while:

    JavaScript для начинающих | Функции

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

    Ок! Давайте же уже разберем, что это за звери такие — функции в JavaScript. Бояться их не стоит. Совсем даже наоборот! Без них нам дальше, ну просто никак.

    Функции в JavaScript и для чего они нужны

    В общем виде функция в JavaScript выглядит так:

    function имя_функции() <
    переменная 1;
    переменная 2;
    alert( ‘ переменная 1 + переменная 2 ‘ );
    >

    Кто уже знаком с версткой сайтов, заметит нечто очень похожее на правила из листа стилей CSS:

    #header <
    max-width: 1200px;
    height: 150px;
    margin: 0 auto;
    >

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

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

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

    Функции в JavaScript: встроенные и создаваемые

    JavaScript имеет множество встроенных функций: alert, prompt, confirm, document.write, Math и др. Мы их пока рассматривать не будем. Как вы уже, наверное, поняли, в JavaScript есть два типа функций: встроенные в язык и создаваемые программистами.

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

    Давайте же напишем нашу первую собственную функцию!

    Ваша первая собственная функция в JavaScript

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

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

    Обратите внимание на две важные особенности этой формы:

    1. В тэге form помимо всех обычных для формы параметров прописан специальный атрибут onsubmit. Об атрибутах в JavaScript мы так же говорили во введении. В данном случае атрибут onsubmit служит для вызова функции проверки формы при нажатии на кнопку «Отправить». У нас эта функция, как видите, называется validate_form ().

    2. Для поля ввода e-mail адреса мы использовали имя (name) — contact_mail. И это же имя мы прописываем в нашей функции в строке условия:

    Внешне наша форма будет выглядеть так:

    Что делает функция в JavaScript

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

    В первой строке после открытия функции мы добавили переменную validation (о переменных будет отдельная статья, не пропустите!). Имя ей можно выбрать произвольное: хоть validation, хоть name_validation, хоть eklmnprst. Главное — это то, что мы присвоили этой переменной значение true, то есть истинно.

    Обратите внимание: знак = это вовсе не равно, а именно присваивание. Иначе можно сказать, что левая сторона выражения приняла значение правой стороны и не более того. Знак же равенства в программировании пишется как ==

    Далее мы пишем условие, начинающееся с if. Об условиях мы так же поговорим отдельно, т.к. это большая и очень интересная тема. В нашем условии мы задаем путь для проверки значения в параметре value поля e-mail адреса. Если оно пустое, то наша переменная validation сразу принимает значение false — ложно. При этом выскакивает, уже знакомое нам, окошко alert с сообщением «Пожалуйста, заполните поле ‘Ваш e-mail’».

    Как вы думаете, почему незаполненное поле выдает ложное значение? Да все просто! В условии мы указываем, что если поле пустое (пустые кавычки в правой части условия после знака равенства ==), то выполняется последующий код условия, в котором срабатывает предупреждение alert. Дальнейшее выполнение кода прерывается. Нам надо закрыть окошко предупреждения и заполнить обязательное поле.

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

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

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

    1. Путь для проверки условия пишется через знак точки. Это чем-то похоже на адреса в браузерной строке, только там разделителем служит знак слэша /, а здесь просто точка. Иначе можно прочитать наше условие так:

    «Если зайти в форму с именем contact_form, а в ней заглянуть в поле contact_mail и там не найти ничего, то сказать пользователю, что он лох».

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

    2. Само условие if так же имеет свой набор правил, взятых в фигурные скобки. Это, так называемое, тело цикла. Пока просто запомните это название, оно вам пригодится в будущем.

    Способы применения функций в JavaScript

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

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

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

    Илон Маск рекомендует:  color в CSS
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL