Функция — это контейнер операторов кода, которые могут быть вызваны с помощью оператора круглых скобок ()
. Параметры могут быть переданы внутри скобок во время вызова, чтобы операторы в функции могли получить доступ к определенным значениям при вызове функции.
В следующем коде мы создаем две версии addNumbers
функции addNumbers: одну с использованием оператора new
а другую — с использованием более распространенного литерального шаблона. Оба ожидают два параметра. В каждом случае мы вызываем функцию, передавая параметры в операторе скобок ()
.
Образец: sample76.html
01
02
03
04
05
06
07
08
09
10
11
12
|
<!DOCTYPE html><html lang=»en»><body><script>
var addNumbersA = new Function(‘num1’, ‘num2’, ‘return num1 + num2’);
console.log(addNumbersA(2, 2));
// Could also be written the literal way, which is much more common.
var addNumbersB = function (num1, num2) { return num1 + num2;
console.log(addNumbersB(2, 2));
</script></body></html>
|
Функцию можно использовать для возврата значения, конструирования объекта или в качестве механизма простого запуска кода. JavaScript имеет несколько применений для функций, но в своей основной форме функция — это просто уникальная область исполняемых операторов.
Function()
Параметры
Конструктор Function()
принимает неопределенное количество параметров, но последний ожидаемый конструктором Function()
является строкой, содержащей операторы, составляющие тело функции. Любые параметры, переданные конструктору до последнего, будут доступны для создаваемой функции. Также возможно отправить несколько параметров в виде строки через запятую.
В следующем коде я сравниваю использование конструктора Function()
с более распространенными шаблонами создания объекта функции.
Образец: sample77.html
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
<!DOCTYPE html><html lang=»en»><body><script>
var addFunction = new Function(‘num1’, ‘num2’, ‘return num1 + num2’);
/* Alternately, a single comma-separated string with arguments can be
the first parameter of the constructor, with the function body following.
var timesFunction = new Function(‘num1,num2’, ‘return num1 * num2’);
console.log(addFunction(2, 2), timesFunction(2, 2));
// Versus the more common patterns for instantiating a function:
var addFunction = function (num1, num2) { return num1 + num2;
function addFunction(num1, num2) { return num1 + num2;
</script></body></html>
|
Непосредственное использование конструктора Function()
не рекомендуется или обычно вообще не делается, потому что JavaScript будет использовать eval()
для анализа строки, содержащей логику функций. Многие считают eval()
ненужными накладными расходами. Если он используется, возможен недостаток в дизайне кода.
Использование конструктора Function()
без ключевого слова new
имеет тот же эффект, что и использование только конструктора для создания объектов функций ( new Function('x','return x')
и function(('x','return x')
).
Закрытие не создается при непосредственном вызове конструктора Function()
.
Function()
Свойства и методы
Объект функции имеет следующие свойства (не включая унаследованные свойства и методы):
Свойства ( Function.prototype;
):
Свойства и методы экземпляра объекта функции
Экземпляры объекта функции имеют следующие свойства и методы (не включая унаследованные свойства и методы):
Свойства экземпляра ( var myFunction = function(x, y, z) {};
myFunction.length;
):
Методы экземпляра ( var myFunction = function(x, y, z) {};
myFunction.toString();
):
Функции всегда возвращают значение
Хотя можно создать функцию просто для выполнения операторов кода, также очень часто функция возвращает значение. В следующем примере мы возвращаем строку из функции sayHi
.
Образец: sample78.html
1
2
3
4
5
6
7
8
9
|
<!DOCTYPE html><html lang=»en»><body><script>
var sayHi = function () {
return ‘Hi’;
};
console.log(sayHi());
</script></body></html>
|
Если функция не указывает возвращаемое значение, возвращается undefined
. В следующем примере мы вызываем функцию yelp
которая записывает строку ‘yelp’ на консоль без явного возврата значения.
Образец: sample79.html
01
02
03
04
05
06
07
08
09
10
11
|
<!DOCTYPE html><html lang=»en»><body><script>
var yelp = function () {
console.log(‘I am yelping!’);
// Functions return undefined even if we don’t.
}
/* Logs true because a value is always returned, even if we don’t specifically return one.
console.log(yelp() === undefined);
</script></body></html>
|
Концепция, которую следует здесь отбросить, заключается в том, что все функции возвращают значение, даже если вы явно не предоставляете возвращаемое значение. Если вы не укажете возвращаемое значение, возвращаемое значение не undefined
.
Функции являются гражданами первого класса (не только синтаксис, но и ценности)
В JavaScript функции являются объектами. Это означает, что функция может храниться в переменной, массиве или объекте. Кроме того, функция может быть передана и возвращена из функции. Функция имеет свойства, потому что это объект. Все эти факторы делают функции первоклассных граждан в JavaScript.
Образец: sample80.html
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<!DOCTYPE html><html lang=»en»><body><script>
// Functions can be stored in variables (funcA), arrays (funcB), and objects (funcC).
var funcA = function () { };
var funcB = [function () { } ];
var funcC = { method: function () { } };
// Functions can be sent to and sent back from functions.
var funcD = function (func) {
return func
};
var runFuncPassedToFuncD = funcD(function () { console.log(‘Hi’); });
runFuncPassedToFuncD();
// Functions are objects, which means they can have properties.
var funcE = function () { };
funcE.answer = ‘yup’;
console.log(funcE.answer);
</script></body></html>
|
Крайне важно, чтобы вы поняли, что функция — это объект и, следовательно, ценность. Его можно передавать или дополнять, как любое другое выражение в JavaScript.
Передача параметров в функцию
Параметры — это средства передачи значений в область действия функции, когда она вызывается. В следующем примере мы вызываем addFunction()
. Так как мы предварительно определили, что он принимает два параметра, в его пределах становятся доступны два дополнительных значения.
Образец: sample81.html
01
02
03
04
05
06
07
08
09
10
|
<!DOCTYPE html><html lang=»en»><body><script>
var addFunction = function (number1, number2) {
var sum = number1 + number2;
return sum;
}
console.log(addFunction(3, 3));
</script></body></html>
|
В отличие от некоторых других языков программирования, в JavaScript вполне допустимо пропускать параметры, даже если функция была определена для принятия этих аргументов. Недостающие параметры просто получают значение undefined
. Конечно, если не указывать значения параметров, функция может работать некорректно.
Если вы передадите функции неожиданные параметры (те, которые не были определены при создании функции), ошибки не возникнет. И к этим параметрам можно получить доступ из объекта arguments
, который доступен для всех функций.
Значения this
и arguments
доступны для всех функций
Внутри области видимости и тела всех функций доступны значения this
и arguments
.
Объект arguments
является массивоподобным объектом, содержащим все параметры, передаваемые в функцию. В следующем коде, несмотря на то, что мы отказываемся указывать параметры при определении функции, мы можем положиться на массив arguments
передаваемый функции, для доступа к параметрам, если они отправляются при вызове.
Образец: sample82.html
1
2
3
4
5
6
7
8
9
|
<!DOCTYPE html><html lang=»en»><body><script>
var add = function () {
return arguments[0] + arguments[1];
};
console.log(add(4, 4));
</script></body></html>
|
Ключевое слово this
, передаваемое всем функциям, является ссылкой на объект, который содержит функцию. Как и следовало ожидать, функции, содержащиеся в объектах как свойства (методы), могут использовать this
для получения ссылки на родительский объект. Когда функция определена в глобальной области видимости, значением this
является глобальный объект. Просмотрите следующий код и убедитесь, что вы понимаете, что он возвращает.
Образец: sample83.html
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<!DOCTYPE html><html lang=»en»><body><script>
var myObject1 = {
name: ‘myObject1’,
myMethod: function () { console.log(this);
};
myObject1.myMethod();
var myObject2 = function () { console.log(this);
myObject2();
</script></body></html>
|
Свойство arguments.callee
У объекта arguments
есть свойство callee
, которое является ссылкой на функцию, выполняемую в данный момент. Это свойство может использоваться для ссылки на функцию изнутри области действия функции ( arguments.callee
) по собственной ссылке. В следующем коде мы используем это свойство, чтобы получить ссылку на вызывающую функцию.
Образец: sample84.html
1
2
3
4
5
6
7
8
|
<!DOCTYPE html><html lang=»en»><body><script>
var foo = function foo() {
console.log(arguments.callee);
// callee could be used to invoke recursively the foo function (arguments.callee())
} ();
</script></body></html>
|
Это может быть полезно, когда функцию необходимо вызывать рекурсивно.
Свойство Экземпляр функции length
и arguments.length
Объект arguments
имеет уникальное свойство length
. Хотя вы можете подумать, что это свойство длины даст вам количество определенных аргументов, на самом деле оно дает количество параметров, отправленных функции во время вызова.
Образец: sample85.html
1
2
3
4
5
6
7
8
9
|
<!DOCTYPE html><html lang=»en»><body><script>
var myFunction = function (z, s, d) {
return arguments.length;
};
console.log(myFunction());
</script></body></html>
|
Используя свойство length
всех экземпляров Function()
, мы можем получить общее количество параметров, ожидаемых функцией.
Образец: sample86.html
1
2
3
4
5
6
7
8
9
|
<!DOCTYPE html><html lang=»en»><body><script>
var myFunction = function (z, s, d, e, r, m, q) {
return myFunction.length;
};
console.log(myFunction());
</script></body></html>
|
Свойство arguments.length
устарело в JavaScript 1.4, но число аргументов, отправляемых функции, можно получить из свойства length
объекта функции. Двигаясь вперед, вы можете получить значение длины, используя свойство callee
чтобы сначала получить ссылку на вызываемую функцию ( arguments.callee.length
).
Переопределение параметров функции
Параметры функции могут быть переопределены внутри функции либо напрямую, либо с помощью массива arguments
. Посмотрите на этот код:
Образец: sample87.html
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
<!DOCTYPE html><html lang=»en»><body><script>
var foo = false;
var bar = false;
var myFunction = function (foo, bar) {
arguments[0] = true;
bar = true;
console.log(arguments[0], bar);
}
myFunction();
</script></body></html>
|
Обратите внимание, что я могу переопределить значение параметра bar, используя индекс arguments
или непосредственно переназначая новое значение параметру.
Возврат функции до ее завершения (отмена выполнения функции)
Функции могут быть отменены в любое время во время вызова с использованием ключевого слова return
со значением или без него. В следующем примере мы отменяем функцию add
если параметры не определены или не являются числом.
Образец: sample88.html
01
02
03
04
05
06
07
08
09
10
11
|
<!DOCTYPE html><html lang=»en»><body><script>
var add = function (x, y) {
// If the parameters are not numbers, return error.
if (typeof x !== ‘number’ || typeof y !== ‘number’) { return ‘pass in numbers’;
return x + y;
}
console.log(add(3, 3));
console.log(add(‘2’, ‘2’));
</script></body></html>
|
Идея, которую следует здесь отбросить, заключается в том, что вы можете отменить выполнение функции, используя ключевое слово return
в любой точке выполнения функции.
Определение функции (оператор, выражение или конструктор)
Функцию можно определить тремя различными способами: конструктор функции, оператор функции или выражение функции. В следующем примере я демонстрирую каждый вариант.
Образец: sample89.html
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
<!DOCTYPE html><html lang=»en»><body><script>
/* Function constructor: The last parameter is the function logic,
everything before it is a parameter.
var addConstructor = new Function(‘x’, ‘y’, ‘return x + y’);
// Function statement.
function addStatement(x, y) {
return x + y;
}
// Function expression.
var addExpression = function (x, y) {
return x + y;
};
console.log(addConstructor(2, 2), addStatement(2, 2), addExpression(2, 2));
</script></body></html>
|
Некоторые говорят, что существует четвертый тип определения функций, называемый «выражением именованной функции». Выражение именованной функции — это просто выражение функции, которое также содержит имя (например, var add = function add(x, y) {return x+y}
).
Вызов функции (Function, Method, Constructor или call()
и apply()
)
Функции вызываются с использованием четырех различных сценариев или шаблонов.
- Как функция
- Как метод
- Как конструктор
- Использование
apply()
илиcall()
В следующем примере мы рассмотрим каждый из этих шаблонов вызова.
Образец: sample90.html
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
<!DOCTYPE html><html lang=»en»><body><script>
// Function pattern.
var myFunction = function () { return ‘foo’ };
console.log(myFunction());
// Method pattern.
var myObject = { myFunction: function () { return ‘bar’;
console.log(myObject.myFunction());
// Constructor pattern.
var Cody = function () {
this.living = true;
this.age = 33;
this.gender = ‘male’;
this.getGender = function () { return this.gender;
}
var cody = new Cody();
console.log(cody);
// apply() and call() pattern.
var greet = {
runGreet: function () {
console.log(this.name, arguments[0], arguments[1]);
}
}
var cody = { name: ‘cody’ };
var lisa = { name: ‘lisa’ };
// Invoke the runGreet function as if it were inside of the cody object.
greet.runGreet.call(cody, ‘foo’, ‘bar’);
// Invoke the runGreet function as if it were inside of the lisa object.
greet.runGreet.apply(lisa, [‘foo’, ‘bar’]);
/* Notice the difference between call() and apply() in how parameters are sent to the function being invoked.
</script></body></html>
|
Убедитесь, что вам известны все четыре шаблона вызова, поскольку код, который вы встретите, может содержать любой из них.
Анонимные функции
Анонимная функция — это функция, которой не присвоен идентификатор. Анонимные функции в основном используются для передачи функций в качестве параметра другой функции.
Образец: sample91.html
01
02
03
04
05
06
07
08
09
10
11
12
13
|
<!DOCTYPE html><html lang=»en»><body><script>
// function(){console.log(‘hi’);};
// Create a function that can invoke our anonymous function.
var sayHi = function (f) {
f();
}
// Pass an anonymous function as a parameter.
sayHi(function () { console.log(‘hi’); });
</script></body></html>
|
Выражение функции самовывоза
Выражение функции (на самом деле любая функция, кроме созданной из конструктора Function()
) может быть немедленно вызвано после определения с помощью оператора скобок. В следующем примере мы создаем выражение функции sayWord()
и затем немедленно вызываем функцию. Это считается самопризывающей функцией.
Образец: sample92.html
1
2
3
4
5
|
<!DOCTYPE html><html lang=»en»><body><script>
var sayWord = function () { console.log(‘Word 2 yo mo!’);
</script></body></html>
|
Самовызывающиеся анонимные функции
Можно создать анонимный оператор функции, который вызывается самостоятельно. Это называется самовозглашающейся анонимной функцией. В следующем примере мы создаем несколько анонимных функций, которые вызываются немедленно.
Образец: sample93.html
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
<!DOCTYPE html><html lang=»en»><body><script>
// Most commonly used/seen in the wild.
(function (msg) {
console.log(msg);
})(‘Hi’);
// Slightly different, but achieving the same thing:
(function (msg) {
console.log(msg)
} (‘Hi’));
// The shortest possible solution.
!function sayHi(msg) { console.log(msg);
// FYI, this does NOT work!
// function sayHi() {console.log(‘hi’);}();
</script></body></html>
|
В соответствии со стандартом ECMAScript скобки вокруг функции (или всего, что преобразует функцию в выражение) требуются, если функция должна быть вызвана немедленно.
Функции могут быть вложенными
Функции могут быть вложены в другие функции бесконечно. В следующем примере кода мы инкапсулируем функцию goo
внутри функции bar
, которая находится внутри функции foo
.
Образец: sample94.html
01
02
03
04
05
06
07
08
09
10
11
|
<!DOCTYPE html><html lang=»en»><body><script>
var foo = function () {
var bar = function () {
var goo = function () {
console.log(this);
} ();
} ();
} ();
</script></body></html>
|
Простая концепция здесь заключается в том, что функции могут быть вложенными, и нет предела тому, насколько глубоким может быть вложение.
Помните, что значением this
для вложенных функций будет объект head (объект window
в веб-браузере) в JavaScript 1.5, ECMA-262, Edition 3.
Передача функций в функции и возврат функций из функций
Как упоминалось ранее, функции являются первоклассными гражданами в JavaScript. А поскольку функция является значением, и функции может быть передано любое значение, функция может быть передана функции. Функции, которые принимают и / или возвращают другие функции, иногда называют «функциями высшего порядка».
В следующем коде мы передаем анонимную функцию в функцию foo
которую мы немедленно возвращаем из функции foo
. Именно на эту анонимную функцию указывает переменная bar
, поскольку foo
принимает, а затем возвращает анонимную функцию.
Образец: sample95.html
01
02
03
04
05
06
07
08
09
10
11
12
|
<!DOCTYPE html><html lang=»en»><body><script>
// Functions can be sent to, and sent back from, functions.
var foo = function (f) {
return f;
}
var bar = foo(function () { console.log(‘Hi’); });
bar();
</script></body></html>
|
Поэтому, когда вызывается bar
, она вызывает анонимную функцию, которая была передана в функцию foo()
, которая затем передается обратно из функции foo()
и ссылается на bar
переменной bar
. Все это для демонстрации того факта, что функции могут передаваться как любое другое значение.
Вызов операторов функций до их определения (так называемый подъем функций)
Оператор функции может быть вызван во время выполнения до его фактического определения. Это немного странно, но вы должны знать об этом, чтобы вы могли использовать это, или, по крайней мере, знать, что происходит, когда вы сталкиваетесь с этим. В следующем примере я sayYo()
операторы функций sayYo()
и sum()
до их определения.
Образец: sample96.html
01
02
03
04
05
06
07
08
09
10
11
12
13
|
<!DOCTYPE html><html lang=»en»><body><script>
// Example 1
var speak = function () {
sayYo();
function sayYo() { console.log(‘Yo’);
} ();
// Example 2
console.log(sum(2, 2));
function sum(x, y) { return x + y;
</script></body></html>
|
Это происходит потому, что перед выполнением кода операторы функций интерпретируются и добавляются в стек / контекст выполнения. Убедитесь, что вы знаете об этом, когда используете операторы функций.
Функции, определенные как выражения функций, не поднимаются. Подняты только операторы функций.
Функция может вызывать себя (она же рекурсия)
Для функции вполне законно вызывать себя. Фактически, это часто используется в известных шаблонах кодирования. В следующем коде мы countDownFrom
функцию countDownFrom
, которая затем вызывает себя через имя функции countDownFrom
. По сути, это создает цикл, который отсчитывает от 5 до 0.
Образец: sample97.html
01
02
03
04
05
06
07
08
09
10
11
12
13
|
<!DOCTYPE html><html lang=»en»><body><script>
var countDownFrom = function countDownFrom(num) {
console.log(num);
num—;
if (num < 0) { return false;
// Could have also done arguments.callee(num) if it was an anonymous function.
countDownFrom(num);
};
countDownFrom(5);
</script></body></html>
|
Вы должны знать, что для функции естественно вызывать себя (она же рекурсия) или делать это многократно.
Вывод
Функции являются одним из наиболее часто используемых аспектов JavaScript, надеюсь, теперь вы лучше понимаете, как их использовать.