Являются ли функции объектами в JavaScript?
Что проверяют
Знаете ли вы, что функция это полноценный объект, и понимаете ли, что из этого следует в повседневном фронтенде. Вопрос звучит теоретически, а проверяет практику: на первоклассных функциях держатся колбеки, обработчики событий и вся мемоизация в React.
Как отвечать
Да, функции в JavaScript это объекты. Они наследуются от Function.prototype, а через него от Object.prototype, у них есть свойства, им можно добавлять свои, и они передаются как любое значение.
function greet(name) { return `Привет, ${name}`; }
typeof greet; // "function"
greet instanceof Object; // true
greet.name; // "greet"
greet.length; // 1, число объявленных параметров
greet.cache = new Map(); // на функцию можно повесить свойство
const bound = greet.bind(null);
bound === greet.bind(null); // false, каждый вызов даёт новую функциюОт обычного объекта функцию отличает внутренняя операция вызова. Поэтому typeof отдаёт для функций отдельное значение, хотя новым типом функция не становится.
На практике отсюда растут три вещи. Функции хранят в переменных, массивах и свойствах объектов: так устроены обработчики и колбеки. Функции возвращают из функций: так устроены замыкания и обёртки. И у функции есть идентичность: две внешне одинаковые функции это два разных объекта.
Где спотыкаются
Отвечают «нет, это отдельный тип, ведь typeof возвращает function». Это историческое исключение для вызываемых значений, а не отдельная ветка типов, и проверка через instanceof Object показывает обычный объект.
Забывают про идентичность там, где она решает всё. Инлайновая стрелка в пропсе создаётся заново на каждый рендер, поэтому memo не спасает от перерисовки, а зависимости хуков считаются изменившимися. По той же причине ломается снятие слушателя: removeEventListener требует ту же ссылку, а bind возвращает новую функцию.
Считают, что раз функция объект, то и обращаться с ней можно как с обычным объектом. Спред и Object.assign копируют только собственные перечислимые свойства и дают невызываемый результат, а у стрелочных нет ни prototype, ни своего this, и через new их не вызвать.