08. Функции. Часть 2. Замыкания

Объект вызова

Давайте посмотрим, как работают функции JavaScript.

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

  1. Для каждого формального аргумента в объекте вызова создается одноименное свойство и в него записывается значение фактического аргумента или undefined, если фактический аргумент отсутствует.
  2. Все локальные переменные функции становятся свойствами объекта вызова.
  3. В объекте вызова создается объект arguments. Как вы помните, этот объект подобен массиву, его свойства arguments[i] содержат значения фактических аргументов, а свойство arguments.length — их количество. Кроме того, объект arguments имеет свойство arguments.callee, содержащее ссылку на саму функцию.

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

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

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

Замечание 1. Отметим, что объект вызова — это не то же самое, что контекст выполнения функции. Контекст выполнения функции — это объект, на который ссылается ключевое слово this в теле функции, а объект вызова — это рабочая область, которая создается на время работы функции (за одним исключением, которое описано в следующем разделе).

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

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

Читаем быстрее следующий раздел — там самое интересное!