Spec-Zone.ru › JavaScript

function expression

Baseline Широко доступно

Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна в браузерах с июля 2015 года.

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

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

Попробуйте

const getRectArea = function (width, height) {
  return width * height;
};

console.log(getRectArea(3, 4));
// Expected output: 12

Синтаксис

function (param0) {
  statements
}
function (param0, param1) {
  statements
}
function (param0, param1, /* …, */ paramN) {
  statements
}

function name(param0) {
  statements
}
function name(param0, param1) {
  statements
}
function name(param0, param1, /* …, */ paramN) {
  statements
}

Примечание: Выражение-инструкция не может начинаться с ключевого слова function, чтобы избежать неоднозначности с function объявлением. Ключевое слово function начинает выражение только тогда, когда оно появляется в контексте, который не может принимать инструкции.

Параметры

name Необязательный
Имя функции. Может быть опущено, в этом случае функция является анонимной. Имя локально только для тела функции.
paramN Необязательный
Имя формального параметра функции. Синтаксис параметров см. в справке по функциям.
statements Необязательный
Инструкции, составляющие тело функции.

Описание

function выражение очень похоже и имеет почти такой же синтаксис, как и function объявление. Основное отличие между function выражением и function объявлением — это имя функции, которое может быть опущено в function выражениях для создания анонимных функций. function выражение может использоваться как IIFE (Immediately Invoked Function Expression — немедленно вызываемое функциональное выражение), которое выполняется сразу после определения. См. также главу о функциях для получения дополнительной информации.

Поднятие (hoisting) функциональных выражений

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

console.log(notHoisted); // undefined
// Even though the variable name is hoisted,
// the definition isn't. so it's undefined.
notHoisted(); // TypeError: notHoisted is not a function

var notHoisted = function () {
  console.log("bar");
};

Именованное функциональное выражение

Если вы хотите обратиться к текущей функции внутри тела функции, вам нужно создать именованное функциональное выражение. Это имя затем локально только для тела функции (области видимости). Это позволяет избежать использования устаревшего arguments.callee свойства для рекурсивного вызова функции.

const math = {
  factorial: function factorial(n) {
    console.log(n);
    if (n <= 1) {
      return 1;
    }
    return n * factorial(n - 1);
  },
};

math.factorial(3); // 3;2;1;

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

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

"use strict";

function foo() {
  foo = 1;
}
foo();
console.log(foo); // 1
(function foo() {
  foo = 1; // TypeError: Assignment to constant variable.
})();

Примеры

Использование функционального выражения

Следующий пример определяет безымянную функцию и присваивает ее x. Функция возвращает квадрат своего аргумента:

const x = function (y) {
  return y * y;
};

Использование функции в качестве обратного вызова

Чаще всего это используется как callback (функция обратного вызова):

button.addEventListener("click", function (event) {
  console.log("button is clicked!");
});

Использование немедленно вызываемого функционального выражения (IIFE)

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

// standard IIFE
(function () {
  // statements…
})();

// IIFE with arguments
(function (a, b) {
  console.log(a + b);
})(1, 2); // logs 3

// IIFE being used to initialize a variable
const value = (() => {
  const randomValue = Math.random();
  if (randomValue > 0.5) {
    return "heads";
  }
  return "tails";
})();

Здесь мы рассмотрим несколько вариантов использования с примерами.

Избегайте загрязнения глобального пространства имен в коде скриптов

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

// top-level of a script (not a module)

var globalVariable = (() => {
  // some initialization code
  let firstVariable = something();
  let secondVariable = somethingElse();
  return firstVariable + secondVariable;
})();

// firstVariable and secondVariable cannot be accessed outside of the function body.

Паттерн модуля

Мы также будем использовать IIFE для создания приватных и публичных переменных и методов. Для более сложного использования паттерна модуля и других вариантов применения IIFE вы можете ознакомиться с книгой "Learning JavaScript Design Patterns" от Addy Osmani.

const makeWithdraw = (balance) =>
  ((copyBalance) => {
    let balance = copyBalance; // This variable is private
    const doBadThings = () => {
      console.log("I will do bad things with your money");
    };
    doBadThings();
    return {
      withdraw(amount) {
        if (balance >= amount) {
          balance -= amount;
          return balance;
        }
        return "Insufficient money";
      },
    };
  })(balance);

const firstAccount = makeWithdraw(100); // "I will do bad things with your money"
console.log(firstAccount.balance); // undefined
console.log(firstAccount.withdraw(20)); // 80
console.log(firstAccount.withdraw(30)); // 50
console.log(firstAccount.doBadThings); // undefined; this method is private
const secondAccount = makeWithdraw(20); // "I will do bad things with your money"
console.log(secondAccount.withdraw(30)); // "Insufficient money"
console.log(secondAccount.withdraw(20)); // 0

Цикл for с var до ES6

Мы могли видеть следующее использование IIFE в старом коде, до появления let и const объявлений с блочной областью видимости. С инструкцией var у нас есть только функциональные области видимости и глобальная область видимости. Предположим, мы хотим создать 2 кнопки с текстом Button 0 и Button 1, и когда мы нажимаем на них, они должны выводить 0 и 1. Следующий код не работает:

for (var i = 0; i < 2; i++) {
  const button = document.createElement("button");
  button.innerText = `Button ${i}`;
  button.onclick = function () {
    console.log(i);
  };
  document.body.appendChild(button);
}
console.log(i); // 2

При нажатии обе кнопки Button 0 и Button 1 выводят 2, потому что i является глобальной, с последним значением 2. Чтобы решить эту проблему до ES6, мы могли использовать шаблон IIFE:

for (var i = 0; i < 2; i++) {
  const button = document.createElement("button");
  button.innerText = `Button ${i}`;
  button.onclick = (function (copyOfI) {
    return function () {
      console.log(copyOfI);
    };
  })(i);
  document.body.appendChild(button);
}
console.log(i); // 2

При нажатии кнопки Buttons 0 и 1 выводят 0 и 1. Переменная i определена глобально. Используя инструкцию let, мы можем просто сделать:

for (let i = 0; i < 2; i++) {
  const button = document.createElement("button");
  button.innerText = `Button ${i}`;
  button.onclick = function () {
    console.log(i);
  };
  document.body.appendChild(button);
}
console.log(i); // Uncaught ReferenceError: i is not defined.

При нажатии эти кнопки выводят 0 и 1.

Инструкции управления потоком в позициях выражений

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

someObject.property = (() => {
  switch (someVariable) {
    case 0:
      return "zero";
    case 1:
      return "one";
    default:
      return "unknown";
  }
})();

Этот подход может быть особенно полезен в сценариях, когда вы хотите сделать переменную const, но вынуждены использовать let или var во время инициализации:

let onlyAssignedOnce;
try {
  onlyAssignedOnce = someFunctionThatMightThrow();
} catch (e) {
  onlyAssignedOnce = null;
}

Используя IIFE, мы можем сделать переменную const:

const onlyAssignedOnce = (() => {
  try {
    return someFunctionThatMightThrow();
  } catch (e) {
    return null;
  }
})();

Спецификации

Спецификация
ECMAScript® 2027 Language Specification
# sec-function-definitions

Совместимость с браузерами

Настольные компьютеры Мобильные устройства Сервер
Chrome Edge Firefox Opera Safari Chrome Android Firefox for Android Opera Android Safari on iOS Samsung Internet WebView Android WebView on iOS Bun Deno Node.js
function
1
12
1
3
1
18
4
10.1
1
1.0
4.4
1
1.0.0
1.0
0.10.0
trailing_comma
58
14
52
45
10
58
52
43
10
7.0
58
10
1.0.0
1.0
8.0.0

См. также

  • Руководство по функциям
  • Функции
  • function
  • Function
  • Стрелочные функции

© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API