Spec-Zone.ru › JavaScript

Функции

Базовая линия Широко доступно

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

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

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

Дополнительные примеры и объяснения см. в руководстве по JavaScript о функциях.

Описание

Значения функций обычно являются экземплярами Function. См. Function для получения информации о свойствах и методах объектов Function. Вызываемые значения приводят к тому, что typeof возвращает "function" вместо "object".

Примечание: Не все вызываемые значения являются instanceof Function. Например, объект Function.prototype является вызываемым, но не является экземпляром Function. Вы также можете вручную установить цепочку прототипов вашей функции, чтобы она больше не наследовала от Function.prototype. Однако такие случаи чрезвычайно редки.

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

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

Примечание: Конструкторы, вызванные с new, имеют другой набор логики для определения своих возвращаемых значений.

Передача аргументов

Параметры и аргументы имеют несколько разные значения, но в веб-документах MDN мы часто используем их как взаимозаменяемые. Для быстрого справки:

function formatNumber(num) {
  return num.toFixed(2);
}

formatNumber(2);

В этом примере переменная num называется параметром функции: она объявлена в списке, заключенном в скобки, определения функции. Функция ожидает, что параметр num будет числом — хотя это и не является обязательным в JavaScript без написания кода валидации во время выполнения. В вызове formatNumber(2) число 2 является аргументом функции: это значение, которое фактически передается в функцию при вызове функции. Значение аргумента можно получить внутри тела функции через соответствующее имя параметра или объект arguments.

Аргументы всегда передаются по значению и никогда не передаются по ссылке. Это означает, что если функция переназначает параметр, значение не изменится вне функции. Точнее, объектные аргументы передаются по общему доступу (sharing), что означает, что если свойства объекта изменяются, изменение повлияет на внешнюю среду функции. Например:

function updateBrand(obj) {
  // Mutating the object is visible outside the function
  obj.brand = "Toyota";
  // Try to reassign the parameter, but this won't affect
  // the variable's value outside the function
  obj = null;
}

const car = {
  brand: "Honda",
  model: "Accord",
  year: 1998,
};

console.log(car.brand); // Honda

// Pass object reference to the function
updateBrand(car);

// updateBrand mutates car
console.log(car.brand); // Toyota

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

Определение функций

В широком смысле, JavaScript имеет четыре типа функций:

  • Обычная функция: может возвращать что угодно; всегда выполняется до конца после вызова
  • Генераторная функция: возвращает объект Generator; может быть приостановлена и возобновлена с помощью оператора yield
  • Асинхронная функция: возвращает Promise; может быть приостановлена и возобновлена с помощью оператора await
  • Асинхронная генераторная функция: возвращает объект AsyncGenerator; могут использоваться как оператор await, так и оператор yield

Для каждого типа функции существует несколько способов ее определения:

Объявление
function, function*, async function, async function*
Выражение
function, function*, async function, async function*
Конструктор
Function(), GeneratorFunction(), AsyncFunction(), AsyncGeneratorFunction()

Кроме того, существуют специальные синтаксисы для определения стрелочных функций и методов, которые обеспечивают более точную семантику их использования. Классы концептуально не являются функциями (поскольку они вызывают ошибку при вызове без new), но они также наследуются от Function.prototype и имеют typeof MyClass === "function".

// Constructor
const multiply = new Function("x", "y", "return x * y");

// Declaration
function multiply(x, y) {
  return x * y;
} // No need for semicolon here

// Expression; the function is anonymous but assigned to a variable
const multiply = function (x, y) {
  return x * y;
};
// Expression; the function has its own name
const multiply = function funcName(x, y) {
  return x * y;
};

// Arrow function
const multiply = (x, y) => x * y;

// Method
const obj = {
  multiply(x, y) {
    return x * y;
  },
};

Все синтаксисы делают примерно одно и то же, но существуют некоторые тонкие поведенческие различия.

  • Конструктор Function(), выражение function и объявление function создают полноценные объекты функций, которые могут быть сконструированы с помощью new. Однако стрелочные функции и методы не могут быть сконструированы. Асинхронные функции, генераторные функции и асинхронные генераторные функции не являются конструируемыми независимо от синтаксиса.
  • Объявление function создает функции, которые подвергаются поднятию (hoisting). Другие синтаксисы не поднимают функцию, и значение функции видимо только после определения.
  • Синтаксис стрелочной функции и конструктор Function() всегда создают анонимные функции, что означает, что они не могут легко вызывать себя рекурсивно. Один из способов рекурсивного вызова стрелочной функции — присвоение ее переменной.
  • Синтаксис стрелочной функции не имеет доступа к arguments или this.
  • Конструктор Function() не имеет доступа к локальным переменным — он имеет доступ только к глобальной области видимости.
  • Конструктор Function() вызывает компиляцию во время выполнения и часто работает медленнее других синтаксисов.

Для выражений function существует различие между именем функции и переменной, которой присвоена функция. Имя функции нельзя изменить, а переменной, которой присвоена функция, можно переназначать. Имя функции может отличаться от переменной, которой присвоена функция — они никак не связаны. Имя функции можно использовать только внутри тела функции. Попытка использовать его вне тела функции приведет к ошибке (или даст другое значение, если то же имя объявлено где-то еще). Например:

const y = function x() {};
console.log(x); // ReferenceError: x is not defined

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

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

Функция, определенная с помощью new Function, будет динамически собирать свой исходный код, что наблюдаемо при ее сериализации. Например, console.log(new Function().toString()) дает:

function anonymous(
) {

}

Это фактический исходный код, используемый для компиляции функции. Однако, хотя конструктор Function() создаст функцию с именем anonymous, это имя не добавляется в область видимости тела. Тело имеет доступ только к глобальным переменным. Например, следующее приведет к ошибке:

new Function("alert(anonymous);")();

Функция, определенная выражением функции или объявлением функции, наследует текущую область видимости. То есть, функция формирует замыкание. С другой стороны, функция, определенная конструктором Function, не наследует никакой области видимости, кроме глобальной (которую наследуют все функции).

// p is a global variable
globalThis.p = 5;
function myFunc() {
  // p is a local variable
  const p = 9;

  function decl() {
    console.log(p);
  }
  const expr = function () {
    console.log(p);
  };
  const cons = new Function("\tconsole.log(p);");

  decl();
  expr();
  cons();
}
myFunc();

// Logs:
// 9 (for 'decl' by function declaration (current scope))
// 9 (for 'expr' by function expression (current scope))
// 5 (for 'cons' by Function constructor (global scope))

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

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

// A function declaration
function foo() {
  console.log("FOO!");
}

doSomething(
  // A function expression passed as an argument
  function foo() {
    console.log("FOO!");
  },
);

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

function () { // SyntaxError: Function statements require a function name
  console.log("FOO!");
}();

function foo() {
  console.log("FOO!");
}(); // SyntaxError: Unexpected token ')'

Вместо этого начните инструкцию выражения с чего-то другого, чтобы ключевое слово function однозначно начинало выражение функции. Распространенные варианты включают группировку и использование void.

(function () {
  console.log("FOO!");
})();

void function () {
  console.log("FOO!");
}();

Параметры функции

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

function myFunc(a, b, c) {
  // You can access the values of a, b, and c here
}

Существуют три специальных синтаксиса параметров:

  • Параметры по умолчанию позволяют инициализировать формальные параметры значениями по умолчанию, если не передано значение или undefined.
  • Параметр rest позволяет представить неопределенное количество аргументов в виде массива.
  • Деструктуризация позволяет распаковывать элементы из массивов или свойства из объектов в отдельные переменные.
function myFunc({ a, b }, c = 1, ...rest) {
  // You can access the values of a, b, c, and rest here
}

Если используется один из вышеуказанных не-простых синтаксисов параметров, возникают некоторые последствия:

  • Вы не можете применить "use strict" к телу функции — это приведет к синтаксической ошибке.
  • Даже если функция не находится в строгом режиме, применяются некоторые функции строгого режима, включая то, что объект arguments перестает синхронизироваться с именованными параметрами, arguments.callee вызывает ошибку при доступе, и дублирующиеся имена параметров не допускаются.

Объект arguments

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

arguments
Объект, похожий на массив, содержащий аргументы, переданные текущей выполняющейся функции.
arguments.callee
Текущая выполняющаяся функция.
arguments.length
Количество аргументов, переданных функции.

Функции геттера и сеттера

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

get
Привязывает свойство объекта к функции, которая будет вызвана при поиске этого свойства.
set
Привязывает свойство объекта к функции, которая будет вызвана при попытке установить это свойство.

Обратите внимание, что эти синтаксисы создают свойство объекта, а не метод. Сами функции геттера и сеттера доступны только с использованием рефлективных API, таких как Object.getOwnPropertyDescriptor().

Функции блочного уровня

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

"use strict";

function f() {
  return 1;
}

{
  function f() {
    return 2;
  }
}

f() === 1; // true

// f() === 2 in non-strict mode

Функции блочного уровня в нестрогом коде

Одно слово: Не делайте этого.

В нестрогом коде объявления функций внутри блоков ведут себя странно. Например:

if (shouldDefineZero) {
  function zero() {
    // DANGER: compatibility risk
    console.log("This is zero.");
  }
}

Семантика этого в строгом режиме хорошо определена — zero существует только в пределах области видимости блока if. Если shouldDefineZero равно false, то zero никогда не должно быть определено, поскольку блок никогда не выполняется. Однако исторически это было не определено, поэтому разные браузеры реализовали это по-разному в нестрогом режиме. Для получения дополнительной информации см. справку по объявлению function.

Более безопасный способ условного определения функций — присвоить выражение функции переменной:

// Using a var makes it available as a global variable,
// with closer behavior to a top-level function declaration
var zero;
if (shouldDefineZero) {
  zero = function () {
    console.log("This is zero.");
  };
}

Примеры

Возврат отформатированного числа

Следующая функция возвращает строку, содержащую отформатированное представление числа, дополненное ведущими нулями.

// This function returns a string padded with leading zeros
function padZeros(num, totalLen) {
  let numStr = num.toString(); // Initialize return value as string
  const numZeros = totalLen - numStr.length; // Calculate no. of zeros
  for (let i = 1; i <= numZeros; i++) {
    numStr = `0${numStr}`;
  }
  return numStr;
}

Следующие инструкции вызывают функцию padZeros.

let result;
result = padZeros(42, 4); // returns "0042"
result = padZeros(42, 2); // returns "42"
result = padZeros(5, 4); // returns "0005"

Определение существования функции

Вы можете определить, существует ли функция, используя оператор typeof. В следующем примере выполняется проверка, имеет ли объект window свойство с именем noFunc, которое является функцией. Если да, то оно используется; в противном случае предпринимаются другие действия.

if (typeof window.noFunc === "function") {
  // use noFunc()
} else {
  // do something else
}

Обратите внимание, что в тесте if используется ссылка на noFunc — после имени функции нет скобок (), поэтому сама функция не вызывается.

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

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

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

Desktop Mobile Server
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
functions
1
12
1
3
1
18
4
10.1
1
1.0
4.4
1
1.0.0
1.0
0.10.0
arguments
1
12
1
3
1
18
4
10.1
1
1.0
4.4
1
1.0.0
1.0
0.10.0
arrow_functions
45
12
22Первоначальная реализация стрелочных функций в Firefox автоматически делала их строгими. Это было изменено начиная с Firefox 24. Теперь требуется использование 'use strict';.
До Firefox 39, символ новой строки (\n) ошибочно разрешался после аргументов стрелочной функции. Это было исправлено в соответствии со спецификацией ES2015, и код, подобный () \n => {}, теперь вызовет SyntaxError в этой и последующих версиях.
32
10
45
22Первоначальная реализация стрелочных функций в Firefox для Android автоматически делала их строгими. Это было изменено начиная с Firefox для Android 24. Теперь требуется использование 'use strict';.
До Firefox для Android 39, символ новой строки (\n) ошибочно разрешался после аргументов стрелочной функции. Это было исправлено в соответствии со спецификацией ES2015, и код, подобный () \n => {}, теперь вызовет SyntaxError в этой и последующих версиях.
32
10
5.0
45
10
1.0.0
1.0
4.0.0
block_level_functions
49
12
46
36
10
49
46
36
10
5.0
49
10
1.0.0
1.0
4.0.0
default_parameters
49
14
15
36
10
49
15
36
10
5.0
49
10
1.0.0
1.0
6.0.0
get
1
12
1.5
9.5
3
18
4
14
1
1.0
4.4
1
1.0.0
1.0
0.10.0
method_definitions
39
12
34
26
9
39
34
26
9
4.0
39
9
1.0.0
1.0
4.0.0
rest_parameters
47
12
15
34
10
47
15
34
10
5.0
47
10
1.0.0
1.0
6.0.0
set
1
12
1.5
9.5
3
18
4
14
1
1.0
4.4
1
1.0.0
1.0
0.10.0

См. также

  • Руководство по функциям
  • Классы
  • function
  • function expression
  • 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/Functions

Spec-Zone.ru

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