Javascript урок 4. javascript функции и объекты

«Поднятие» переменных и функций

Интерпретатор JavaScript всегда перемещает («поднимает») объявления функций и переменных в начало области видимости. Если переменная определена внутри функции, она поднимается к верхней части функции, а если переменная определена глобально — к верхней части глобального контекста. Рассмотрим, что это значит на примере:

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

В случае с функциями, поднимается вся функция целиком, если речь идет о функциях-объявлениях (declaration); функция-выражение (expression) не поднимается:

В этом этом примере поднимается только функция . Идентификатор «anomFunc» (переменная, которой присвоена функция) также поднимается, но сама анонимная функция при этом остаётся на месте (как и в случае с пременной).

Javascript функции с параметрами (аргументами) и возврат значений

Рассмотрим подробнее использование инструкции в функции javascript на двух примерах. Кроме того, рассмотрим использование в Javascript функции с параметрами (аргументами).

⇒ 1. Функция в качестве процедуры.
Функция в качестве процедуры возвращает значение , но выполняет какие-то действия:

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

Решение: 

  • Объявите функцию sayHello. В скобках аргументов функции укажите аргумент с именем userName:
1
2
3
4
function sayHello(userName)
{
...
}

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

1
2
3
4
function sayHello(userName)
{
	alert("Привет, " + userName);
}

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

1
2
3
...
sayHello("Вася");
sayHello("Петя");

Переменная userName примет то значение, которое указано в скобках при вызове функции — «Вася» и «Петя». Значит, при первом вызове функция выведет в диалоговое окно Привет, Вася, при втором — Привет, Петя.
Протестируйте результат в браузере.

⇒ 2. Функция в роли функции (классическое оформление).
Функция в классическом оформлении возвращает конкретное значение.

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

Решение: 

  • Объявите функцию sayHello. В скобках аргументов функции укажите аргумент с именем userName:

1
2
3
4
function sayHello(userName)
{
	...
}

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

1
2
3
4
function sayHello(userName)
{
	return "Привет, " + userName;
}

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

1
2
3
...
let a = sayHello("Вася");
alert(a);

Протестируйте результат в браузере.

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

Задание js4_4. Что выведет на экран следующий код?

1
2
3
4
5
6
7
8
9
10
11
let a = 5, b = 10, c = 20, d = 7;
function Sum1() {
 let result = a + b;
 document.write("Sum1: " + result + "<br/>");
}
function Sum2(x1, x2) {
 let result = x1 + x2;
 document.write("Sum2: " + result);
}
Sum1();
Sum2(c, d);

Задание js4_5. Необходимо запросить у пользователя ввести возраст (метод ). Вызывать функцию, которая выводит диалоговое окно с сообщением ‘Привет, малыш!’, если возраст менее 18, и ‘Здравствуйте, юноша!’, если возраст более или равен 18.
У функций могут быть необязательные аргументы:
  Пример:

function f(x, y = 3) {
	return x + y;
}
f(2); // 5

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

  1. классический синтаксис
function a1(x, y) { 
   return x + y; 
}

явное создание объекта

//обязательным является только последний аргумент – тело функции 
let a1 = new Function('x', 'y', 'return x + y');

или

let a1 = new Function('return "hello"');

еще один вариант создания

let a1 = function(x, y) { return x + y; };

Вызов функций во всех случаях будет:

let a = a1(3, 4);
alert(a); // вывод значения на экран

Немедленно исполняемые функторы (Immediately-invoked function expressions, IIFE): var E = (function(){return function(){}})();

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

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

var foo = function(){
    return 'bar';
};
var output = foo();
console.log(output); // 'bar'

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


var foo = function(){
return ‘bar’;
};
var output = (foo)(); // обратите внимание на дополнительные операторы группировки
console.log(output); // ‘bar’

Поскольку foo указывает на на наше функциональное выражение, мы знаем, что можем просто не использовать переменную «foo» и вставить всю функцию как анонимную (ведь функции являются объектами первого класса!):

var output = (function(){
    return 'bar';
})();
console.log(output); // 'bar'

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

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

var E = (function(){
    return function(){}
})();

Приложения

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

Объявления функций: function A(){};

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

1. Hoisting (поднятие переменной)

Интересно, что функции «поднимаются» (hoist) в самый верх их области видимости, а это означает, что данный код:

A();
function A(){
    console.log('foo');
};

исполняется, как этот код:

function A(){
    console.log('foo');
};
A();

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

2. Никаких объявлений функций в блоках if или циклах и т.д.)

Таким способом нельзя определять функции в выражениях, например, в блоках if, что достаточно часто нужно, если мы хотим определить разные версии функции для разных обстоятельств, обычно, чтобы подстроиться под разные браузеры. Конечно, в некоторых случаях вы можете это сделать, но получившийся код будет неконсистентным (kangax задокументировал неконсистентности здесь). Если хотите использовать этот паттерн, лучше пользуйтесь функциональными выражениями.

3. Объявления функций должны иметь имена

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

Параметры

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

В нижеприведённом примере функции передаются два параметра: и .

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

Вот ещё один пример: у нас есть переменная , и мы передаём её функции

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

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

Другими словами:

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

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

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

Объект arguments

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

Свойство этого объекта содержит число переданных аргументов.

На­пишем функцию, вычисляющую сумму произвольного числа аргумен­тов:

Выполнить код »
Скрыть результаты

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

Поскольку он похож на массив, обратиться к переданным функции аргументам можно так же, как и к элементам массива: первый аргумент будет доступен в теле функ­ции как элемент массива arguments,

второй аргумент

arguments

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

Выполнить код »
Скрыть результаты

Объявление Function Declaration

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

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

Позвольте еще раз выделить основной смысл объявления Function Declaration:

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

Другими словами, объявление

function func(параметры) { код } 

говорит интерпретатору: «создай переменную func, и положи туда функцию с указанными параметрами и кодом».

При этом func — на самом деле не «имя функции», оно совсем никак (по стандарту) не привязано к функции! Это название переменной, в которую будет помещена функция, и из которой она может быть затем удалена, скопирована в другую переменную, и в результате её как func вызвать будет нельзя:

function func() { }
var g = func;
func = null;
func(); // ошибка! надо g()

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

// Нонсенс!
function f() { } // объявить переменную f и записать в нее функцию
var f = 5; // объявить переменную f (а она уже объявлена) и присвоить 5
alert(f); // 5

В примере выше переменная f в первой строке получает значение — функцию, а во второй — число 5. В итоге мы получим переменную со значением f=5.

Время создания Function Declaration

Функции, объявленные как Function Declaration, создаются в момент входа в область видимости.

Буквально, происходит следующее. Браузер видит скрипт. Сканирует его на предмет наличия Function Declaration — и для каждого создаёт функцию. (примечание — вложенные функции пока не трогаем, которые будут рассмотрены позже). А потом начинает выполнять код.

Поэтому функцию можно вызывать до объявления:

sayHi("Вася");
function sayHi(name) {
 alert("Привет, " + name);
}

Этот код будет работать, т.к. объявление function sayHi обрабатывается и функция создается до выполнения первой строчки кода.

Условно объявить функцию через Function Declaration нельзя

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

var age = 18;
if (age >= 18) {
  function sayHi() {  alert('Прошу вас!');  }
} else {
  function sayHi() {  alert('До 18 нельзя'); }
}
sayHi();

Какой вызов сработает?

Чтобы это понять — вспомним, как работают функции.

Объявления обрабатываются до выполнения первой строчки кода.
Браузер сканирует код и создает из таких объявлений функции. При этом второе объявление перезапишет первое.

Дальше, во время выполнения объявления игнорируются (они уже обработаны), как если бы код был таким:

var age = 18;
if (age >= 18) {} 
else {}
sayHi();

Как видно, конструкция if ни на что не влияет.

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

Возвращаемое значение (return)

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

Если оно не указано, то вместо этого значения будет возвращено .

Без использования :

С использованием :

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

Функция, которая возвращает функцию

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

Например:

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

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

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

Функцию, приведённую в коде мы можем также создать и так:

Кроме этого в качестве результата мы можем также возвратить внешнюю функцию:

Рекурсия

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

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

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

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

Перегрузка функций в JavaScript

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

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

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

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

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

Возвращение значений

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

В этом коде определяется функция с параметрами х и у. Затем функция получает значения 9 и 7. Запустите программу:

Программа сложит полученные значения, 9 и 7, и вернет результат 16.

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

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

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

Пример объявления функции:

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

Наша новая функция может быть вызвана по её имени: .

Например:

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

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

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

7. Прототипная связь функций

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

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

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

Возникает резонный вопрос: если прототип всякой функции ссылается на , то что является прототипом самой функции ? Ответ: также ссылается на . В принципе это логично, ибо и сама является функцией.

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

JavaScript Функции

Функция (function) – это самостоятельный фрагмент кода, решающий определенную задачу. Каждой функции присваивается уникальное имя, по которому ее можно идентифицировать и «вызвать» в нужный момент.

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

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

Приоритет способов привязки this

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

  • Сначала проверяет, не вызвана ли функция как конструктор с ключевым словом . В этом случае контекстом всегда будет пустой объект;
  • Затем смотрит на фиксированные привязки ();
  • Потом на явные привязки или ;
  • После этого пытается неявно привязать к объекту, если функция вызвана как метод (через точку или квадратные скобки);
  • Если и это не удается (обычный вызов функции), то в качестве контекста выполнения устанавливается глобальный объект () или .

Более сложные примеры замыканий

Использование тройного замыкания и «приватная» функция

var makeCounter = function() {
  var privateCounter = 0;
  function changeBy(val) {
    privateCounter += val;
  }
  return {
    increment: function() {
      changeBy(1);
    },

    decrement: function() {
      changeBy(-1);
    },

    value: function() {
      return privateCounter;
    }
  }
};

var counter = makeCounter();

alert(counter.value());  // 0.

counter.increment();
counter.increment();
alert(counter.value()); // 2.

counter.decrement();
alert(counter.value()); // 1.


В этом примере можно наблюдать интересный эффект: попытка выполнить  приводит к ошибке.

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

А три функции , и наоборот являются как бы публичными (public). И более того: они имеют общее лексическое окружение, заключенное в блоке после ключевого слова return. Да, и так тоже можно!

Обработка Ajax-запроса

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

Рассмотрим пример:

function sendAjax(){ 
    var outerVar = "abc"; 
    $.ajax({ 
       cache : ..., 
       url : ..., 
       type : ..., 
       crossDomain: ..., 
       data : ...., 
       contentType : ..., 
       timeout : 20000, 
       dataType : ..., 
       success : function(response){ 
            console.log(outerVar);	 
        }, 
       error : function(jXhr, err){ 
            console.log(outerVar);	 
        }, 
       xhrFields: { 
           withCredentials: true 
       } 
  }); 
} 

Здесь — та самая внешняя функция. Внутри нее определена функция, которая запускается, если процесс отправки Ajax-запроса завершился успешно (success). Эта callback-функция использует внешнюю переменную outerVar:

Что и требовалось доказать.

Работа с DOM

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

Допустим, нужно устанавливать новый размер шрифта по нажатию кнопок, расположенных на HTML-странице:

Работа с DOM

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

function makeSizer(size) {
  return function() {
    document.body.style.fontSize = size + 'px';
  };
}

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

var size12 = makeSizer(12);
var size14 = makeSizer(14);
var size16 = makeSizer(16);

Тогда , и — это отдельные функции, которые устанавливают размер шрифта страницы равным 12, 14 и 16 пикселей соответственно.

JavaScript Функции

Функция JavaScript — это блок кода, предназначенный для выполнения определенной задачи.

Функция JavaScript выполняется, когда ее вызывают (вызвает) «что-то».

Пример

Синтаксис функции JavaScript

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

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

Скобки могут включать имена параметров, разделенные запятыми: (parameter1, parameter2, . )

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

Параметры функции перечислены в скобках () в определении функции.

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

Внутри функции аргументы (параметры) действуют как локальные переменные.

Функция во многом похожа на процедуру или подпрограмму на других языках программирования.

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

Код внутри функции будет выполняться, когда «что-то» вызывает (вызывается) функцию:

  • Когда происходит событие (когда пользователь нажимает кнопку)
  • Когда он вызывает (вызывается) из кода JavaScript
  • Автоматически (вызывается самостоятельно)

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

Возврат функции

Когда JavaScript достигает return оператора, функция прекращает выполнение.

Если функция была вызвана из оператора, JavaScript «вернется» для выполнения кода после вызывающего оператора.

Функции часто вычисляют возвращаемое значение. Возвращаемое значение «возвращается» обратно «вызывающему»:

Пример

Вычислите произведение двух чисел и верните результат:

var x = myFunction(4, 3); // Функция вызывается, возвращаемое значение будет в конечном итоге в x

function myFunction(a, b) <return a * b; // Функция возвращает произведение a и b >

Результат в x будет:

Почему функции?

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

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

Пример

Преобразовать Фаренгейты в Цельсия:

Оператор () вызывает функцию

В приведенном выше примере toCelsius ссылка на объект функции и toCelsius() ссылка на результат функции.

Доступ к функции без () вернет объект функции вместо результата функции.

Пример

Функции, используемые как значения переменных

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

Пример

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

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

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

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

Переменные, объявленные в функции JavaScript, становятся ЛОКАЛЬНЫМИ для функции.

Доступ к локальным переменным возможен только из функции.

Пример

// код здесь, нельзя использовать carName

function myFunction() <var carName = «Вольво»; // код здесь, можно использовать carName >

// код здесь, нельзя использовать carName

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

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

Проводим вызов PHP функции из JavaScript

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

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

$.ajax({
	url:"script.php",
	data:"id=2",
	success:function(prin){
	$(".data").html(prin);
	}
	})

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

Надеемся, что эта статья оказалась для вас полезной! Удачи!

Вместо заключения: убираем за собой

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

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

function f() {
  let value = 123;

  return function() {
    alert(value);
  }
}

let g = f(); // g.`Environment` хранит ссылку на объект лексического окружения функции f()

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

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

function f() {
  let value = Math.random();

  return function() { alert(value); };
}

/* Создадим массив из трех функций f(). В этом случае каждый экземпляр функции (напоминаю, в JS функция — это тоже объект) хранит свою копию объекта лексического окружения */

let arr = ;

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

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

Рейтинг
( Пока оценок нет )
Editor
Editor/ автор статьи

Давно интересуюсь темой. Мне нравится писать о том, в чём разбираюсь.

Понравилась статья? Поделиться с друзьями:
Люкс-хост
Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: