This

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

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


Локальные переменные — это те переменные, которые объявлены внутри самой функции. И они действительны только внутри данной функции. За её пределами, локальные переменные уже не будут работать.

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

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

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

Вызываем функцию other(), и если теперь попробуем вывести значение переменной x, то в результате увидим цифру 4.

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

var x = 8;

function increment(){
    x++;
}

//Вызываем функцию increment()
increment();

alert(x); //Результат: 9

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

var g = 100;

function func(){
    var g = 14;
    g *= 2; // Это тоже самое что g = g * 2
    alert(g);//Результат: 28
}

//Вызываем функцию.
func();

alert(g);//Результат: 100

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

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

Задачи

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

Тогда поделитесь ею с друзьями и подпишитесь на новые интересные статьи.

Поделиться с друзьями:

Подписаться на новые статьи:

Поддержите пожалуйста мой проект!

Добавляйтесь ко мне в друзья в:

  • — ВКонтакте
  • — Facebook
  • — Одноклассниках

Добавляйтесь в мои группы:

  • — Группа в ВКонтакте
  • — Группа в Facebook
  • — Группа в Одноклассниках

Подпишитесь на мои каналы:

  • — Мой канал на Youtube
  • — Мой канал на Google+

Автор статьи: Мунтян Сергей

Копирование материалов с сайта sozdatisite.ru ЗАПРЕЩЕНО!!!

Дата добавления: 2016-10-21 04:30:37

Функции через =>

Появился новый синтаксис для задания функций через «стрелку» .

Его простейший вариант выглядит так:

Эти две записи – примерно аналогичны:

Как видно, – это уже готовая функция. Слева от находится аргумент, а справа – выражение, которое нужно вернуть.

Если аргументов несколько, то нужно обернуть их в скобки, вот так:

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

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

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

Функции-стрелки очень удобны в качестве коллбеков, например:

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

JS Учебник

JS ГлавнаяJS ВведениеJS УстановкаJS ВыводJS СинтаксисJS ЗаявленияJS КомментарииJS ПеременныеJS ОператорыJS АрифметикаJS ПрисваиванияJS Типы данныхJS ФункцииJS ОбъектыJS ОбластьJS СобытияJS СтрокиJS Методы строкJS ЧислаJS Методы чиселJS МассивыJS Методы массиваJS Сортировка массиваJS Итерация массиваJS ДатыJS Формат датыJS Метод получения датJS Методы набора…JS Математические…JS Случайные числаJS БулевыJS Сравнение…JS Заявления if…elseJS Заявление switchJS Цикл forJS Цикл whileJS Заявление break…JS Преобразование…JS Битовые…JS Регулярные выраженияJS ОшибкиJS ОтладчикJS ПодъемныйJS СтрогийJS Ключевое слово thisJS Руководство стиляJS ПрактикаJS Распространенные ошибкиJS ЭффективностьJS Зарезервированные словаJS ВерсииJS Версия ES5JS Версия ES6JS JSON

Сборка мусора

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

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

…Но, если есть вложенная функция, которая всё ещё доступна после выполнения , то у неё есть свойство , которое ссылается на внешнее лексическое окружение, тем самым оставляя его достижимым, «живым»:

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

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

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

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

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

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

Одним из важных побочных эффектов в V8 (Chrome, Opera) является то, что такая переменная становится недоступной при отладке.

Попробуйте запустить следующий пример в Chrome с открытой Developer Tools.

Когда код будет поставлен на паузу, напишите в консоли .

Как вы можете видеть – такой переменной не существует! В теории, она должна быть доступна, но попала под оптимизацию движка.

Это может приводить к забавным (если удаётся решить быстро) проблемам при отладке. Одна из них – мы можем увидеть не ту внешнюю переменную при совпадающих названиях:

До встречи!

Эту особенность V8 полезно знать. Если вы занимаетесь отладкой в Chrome/Opera, рано или поздно вы с ней встретитесь.

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

Функции которые возвращают какое-то значение

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

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

Для того чтобы лучше понять о чем идёт речь, вспомним такие методы как prompt() и confirm(). Эти методы именно возвращают значение, полученное от пользователя, а не выводят его.


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

function lastElement(arr){
    //Возвращаем последний элемент переданного массива
    return arr;
}

//Объявляем массив
var otherArr = ;

//Вызываем созданную функцию lastElement и в качестве параметра передаем ей созданный массив otherArr
var lastEl = lastElement(otherArr);

//Выводим полученный последний элемент массива
alert(lastEl); 

В результате мы получим слово ‘twix’, так как именно это слово и есть последний элемент массива otherArr.

Метод alert() ничего не возвращает. То есть если мы попытаемся выводить переменную которая типа содержит результат вызова метода alert(), то увидим значение undefined. Это тоже самое как попытаться выводить значение пустой переменной.

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

//Выводим полученный последний элемент массива
var resAlert = alert(lastEl);
var test;

writeText(resAlert); //undefined
writeText(test); //undefined

Как видим в обоих случаях получили значение undefined.

Лексическое окружение

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

Мы будем называть этот объект «лексическое окружение» или просто «объект переменных».

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

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

Посмотрим пример, чтобы лучше понимать, как это работает:

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

  1. До выполнения первой строчки её кода, на стадии инициализации, интерпретатор создаёт пустой объект и заполняет его.

    В данном случае туда попадает аргумент и единственная переменная :

  2. Функция выполняется.

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

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

Тонкости спецификации

Если почитать спецификацию ECMA-262, то мы увидим, что речь идёт о двух объектах: и .

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

Более формальное описание находится в спецификации ECMA-262, секции 10.2-10.5 и 13.

Синтаксис

Синтаксис для объявления функции:

Функция создаётся с заданными аргументами и телом .

Это проще понять на конкретном примере. Здесь объявлена функция с двумя аргументами:

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

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

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

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

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

Примеры методов

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

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

Затем мы вызвали её. Теперь пользователь может говорить!

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

Итак, мы получили метод объекта .

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

Объектно-ориентированное программирование

Когда мы пишем наш код, используя объекты для представления сущностей реального мира, – это называется объектно-ориентированное программирование или сокращённо: «ООП».

ООП является большой предметной областью и интересной наукой само по себе. Как выбрать правильные сущности? Как организовать взаимодействие между ними? Это – создание архитектуры, и есть хорошие книги по этой теме, такие как «Приёмы объектно-ориентированного проектирования. Паттерны проектирования» авторов Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес или «Объектно-ориентированный анализ и проектирование с примерами приложений» Гради Буча, а также ещё множество других книг.

Существует более короткий синтаксис для методов в литерале объекта:

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

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

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

Объявление и вызов функции

Существует три способа объявления функции: Function Declaration, Function Expression и Named Function Expression.


Function Declaration (сокращённо FD) – это «классическое» объявление функции. В JavaScript функции объявляются с помощью литерала функции. Синтаксис объявления FD:

function идентификатор (параметры) { инструкции }

Литерал функции состоит из следующих четырёх частей:

  1. Ключевое слово .
  2. Обязательный идентификатор, определяющий имя функции. В качестве имени функции обычно выбирают глагол, т. к. функция выполняет действие.
  3. Пара круглых скобок вокруг списка из нуля или более идентификаторов, разделяемых запятыми. Данные идентификаторы называются параметрами функции.
  4. Тело функции, состоящее из пары фигурных скобок, внутри которых располагаются инструкции. Тело функции может быть пустым, но фигурные скобки должны быть указаны всегда.

Простой пример:

function sayHi() {
  alert("Hello");
}

Встречая ключевое слово интерпретатор создаёт функцию и затем присваивает ссылку на неё переменной с именем sayHi (переменная с данным именем создаётся интерпретатором автоматически).

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

alert(sayHi);   // function sayHi() { alert("Hello"); }

Function Expression (сокращённо FE) – это объявление функции, которое является частью какого-либо выражения (например присваивания). Синтаксис объявления FE:

function (параметры) { инструкции }

Простой пример:

var sayHi = function () {
  alert("Hello");
};

Функцию FE иначе ещё называют «анонимной функцией».

Named Function Expression (сокращённо NFE) – это объявление функции, которое является частью какого-либо выражения (например присваивания). Синтаксис объявления NFE:

function идентификатор (параметры) { инструкции }

Простой пример:

var sayHi = function foo() {
  alert("Hello");
};

Объявления FE и NFE обрабатываются интерпретатором точно так же, как и объявление FD: интерпретатор создаёт функцию и сохраняет ссылку на неё в переменной sayHi.

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

function sayHi() {
  alert("Hello");
}

var sayHi2 = function () {
  alert("Hello2");
};

var sayHi3 = function foo() {
  alert("Hello3");
};
sayHi();    // "Hello"
sayHi2();   // "Hello2"
sayHi3();   // "Hello3"

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

// Вызов функции до её объявления в коде верхнего уровня
foo();

function foo() {
  alert("Вызов функции foo() в глобальной области видимости.");

  // Вызов функции до её объявления в области видимости функции
  bar();
  function bar() {
    alert("Вызов функции bar() в области видимости функции.");
  }
}

Функции, объявленные как FE или NFE, создаются в процессе выполнения кода, поэтому их можно вызывать только после того как они объявлены:

// sayHi();  // Ошибка. Функция sayHi ещё не существует

var sayHi = function () {
  alert("Hello!");
};

sayHi();

Функции, объявленные внутри блока, находятся в блочной области видимости:

// foo();   // Ошибка. Функция не объявлена.
{
  foo();   // 1
  function foo() {
    console.log(1);
  }
}

foo();    // Ошибка. Функция не объявлена.

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

(function sayHi(str) {
  if (str) { return; }
  sayHi("hi");   // Имя доступно внутри функции
})();

sayHi();         // Ошибка. Функция не объявлена

Функции-стрелки не имеют своего this

Внутри функций-стрелок – тот же , что и снаружи.

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

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

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

При запуске будет «попытка прочитать свойство у «, так как при запуске не ставит . То есть, внутри будет .

Функции стрелки нельзя запускать с

Отсутствие у функции-стрелки «своего » влечёт за собой естественное ограничение: такие функции нельзя использовать в качестве конструктора, то есть нельзя вызывать через .

=> это не то же самое, что

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

  • Вызовом мы передаём текущий , привязывая его к функции.
  • При привязки не происходит, так как функция стрелка вообще не имеет контекста . Поиск в ней осуществляется так же, как и поиск обычной переменной, то есть, выше в замыкании. До появления стандарта ES-2015 такое было невозможно.

Пользовательские свойства

Мы также можем добавить свои собственные свойства.

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

Свойство не есть переменная

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

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

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

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

Это хуже или лучше, чем использовать замыкание?

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

Поэтому выбор реализации зависит от наших целей.

Arrow Functions

Arrow functions allows a short syntax for writing function expressions.

You don’t need the keyword, the keyword, and the curly brackets.

// ES5 var x = function(x, y) {   return x * y; } // ES6 const x = (x, y) => x * y;

Arrow functions do not have their own . They are not well suited for defining object methods.

Arrow functions are not hoisted. They must be defined before they are used.

Using is safer than using , because a function expression is always constant value.

You can only omit the keyword and the curly brackets if the function is a single statement. Because of this, it might be a good habit to always keep them:

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

Или даже так:

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

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

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

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

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

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

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

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

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

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

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

Вызов функции как метода

В JavaScript можно определить функции как методы объектов.

В следующем примере создается объект (myObject) с двумя свойствами (firstName и lastName) и метод (fullName):

Пример

var myObject = {   firstName:»Андрей»,   lastName: «Щипунов»,   fullName: function () {     return this.firstName + » » + this.lastName;   } } myObject.fullName(); // Будет возвращать «Андрей Щипунов»

Метод fullName — это функция. Функция принадлежит объекту myObject является владельцем функции.

То, что называется , является объектом, который «владеет» кодом JavaScript. В данном случае значение является myObject.

Проверьте! Измените метод fullName, чтобы вернуть значение :

Пример

var myObject = {  firstName:»Андрей»,   lastName: «Щипунов»,   fullName: function () {     return this;   }} myObject.fullName(); // Вернет (владельц object)

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

Свойство «length»

Ещё одно встроенное свойство «length» содержит количество параметров функции в её объявлении. Например:

Как мы видим, троеточие, обозначающее «остаточные параметры», здесь как бы «не считается»

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

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

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

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

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

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

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

Итого

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

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

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

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

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

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

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


С этим читают