W3docs

Объект функции и NFE в JavaScript

Функции в JavaScript — объекты: изучите свойства name и length, пользовательские свойства и Named Function Expressions (NFE) для рекурсии.

Функции — это объекты

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

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

Эта страница предполагает, что вы знакомы с выражениями функций. Если конструкция let f = function() {...} вам незнакома, сначала прочтите ту главу.

Свойство name

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

javascript— editable

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

javascript— editable

Однако никакой магии, работающей всегда, нет. Если имени нет и скопировать его не откуда — например, для функции, созданной внутри array, — name будет пустой строкой:

javascript— editable

Свойство name удобно для логирования и отладки: трассировка стека, в которой написано at sayHi, гораздо информативнее, чем at <anonymous>.

Свойство length

Свойство length функции возвращает количество параметров, объявленных в её определении. Rest-параметры (...rest) и параметры со значениями по умолчанию не учитываются, и подсчёт останавливается на первом таком параметре.

javascript— editable

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

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

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

Классический пример — счётчик вызовов:

javascript— editable

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

Named Function Expressions (NFE)

Named Function Expression — это выражение функции, которое несёт имя после ключевого слова function:

let sayHi = function func(who) {
  console.log("Hello, " + who);
};

Это выглядит необычно — зачем давать имя тому, что уже присвоено переменной sayHi? Имя func здесь особенное по двум причинам:

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

Почему внутреннее имя важно

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

javascript— editable

Если бы функция вызывала sayHi("Guest") вместо func("Guest"), вызов бросил бы TypeError, потому что sayHi было присвоено значение null. Внутреннее имя защищено от этого.

NFE и рекурсия

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

javascript— editable

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

Когда использовать эти возможности

  • Используйте name для более понятных логов и отладочного вывода.
  • Используйте length, когда пишете библиотеки, адаптирующиеся к количеству аргументов колбэка.
  • Используйте пользовательские свойства, чтобы дать функции постоянное состояние (счётчики, кеши, конфигурацию) без окружающего замыкания или глобальной переменной.
  • Используйте Named Function Expression всякий раз, когда выражение функции должно вызывать само себя — особенно для рекурсии или отсоединяемых обработчиков, — чтобы вызов работал после переприсвоения переменной.

Итог

Функция JavaScript — это object, который можно исследовать и расширять. Свойство name содержит её имя (часто заполняется контекстно), length сообщает количество объявленных параметров, а пользовательские свойства можно добавлять для постоянного состояния. Named Function Expression добавляет имя, видимое только внутри функции, что позволяет функции надёжно вызывать саму себя — это самый безопасный способ написать самоссылочные и рекурсивные выражения функций.

Практика

Практика
Что такое NFE (Named Function Expression) в JavaScript?
Что такое NFE (Named Function Expression) в JavaScript?
Was this page helpful?