Источник: http://forum.jscourse.com/t/05-konspekt-funkczii/584
Автор конспекта: @Nikolay
Правки: @dmitry
Функции - это некоторые действия. Функция позволяет структурировать программу, разбивать ее на маленьке части (подпрограммы)и таким образом организовывать код.
При создании функции необходимо необходимо ее реализовывать так, чтобы функция имела как можно меньше побочных эффектов.
Если можно избежать в функции обращение к внешним данным (находящимся за пределами функции), и реализовать все через аргументы и возвращаемые значения, то функцию следует реализовывать именно таким образом.
Абстракция - этим термином описывают технику, когда за одним действием скрывается несколько других действий.
При создании функции, к примеру f
, мы можем вызвать ее с помощью console.log(f())
:
function f() {
return 999;
}
console.log(f()); // 999
Также мы можем записать эту функцию в переменную:
var a = f;
Присвоение, сравнивание функций происходит "по ссылке". То есть переменная а
и переменная f
, ссылаются на одну и ту же функцию.
Если мы обратимся к переменной а
или f
,то они вычисляются в ту функцию, в которую ссылаются а
console.log(a === f); // true
Чтобы вызвать функцию следует использовать круглые скобки:
a();
Функция - это значения, и поэтому мы можем передавать их в качестве аргументов в другие функции. Такая техника используется часто в асинхронном программировании и при работе с API.
Создадим функцию которая вызывает аргумент 10 раз:
function run10Times(func) { // принимает аргументом обьект функции (func)
for (var i = 0; i < 10; i += 1) { // вызывает обьект этой функции 10 раз
func();
}
}
Обьявляем функцию run10Times
и передаем в качестве аргумента функцию f
(а если точнее - ссылку на функцию).
function f(timeCalled) {
console.log(999, timeCalled);
}
run10Times(f); // <<
Когда вызывается функция с аргументами, и подставляем другую функцию/обьект (f
) в качестве аргумента, то первым делом запускается тело этой (передаваемой) функции (f
), и те аргументы которые были подставлены при вызове записываются в переменные которые были обьявлены при обьявлении функции.
То есть, внутри run10Times
есть переменнаяfunc
, которая ссылается на ту же функцию, что и f
.
Function declaration
function f() {
console.log(arguments);
}
функия может быть вызвана и работать с любым количеством параметров:
f('mama'); // [ "mama" ]
f('mama', 'mila'); // ["mama", "mila"]
Об аргументах функции удобно думать следующим образом: "Когда функция f
будет вызвана, то в переменную first
внутри функции будет записано то значение, которое передано в качестве первого аргумента при вызове".
Примитивные типы данных (строки, числа, булевые) передается аргументами в функцию по значению. Объекты, массивы, функции передаются по ссылке(!).
Если функцию обьявлена с 3-я параметрами, а при вызове одно из значений не было передано, то в значение непереданных аргументом будет записано значение undefined
.
function f(first, second, third) {
console.log(first, second, third);
console.log('arguments', arguments);
}
f('first'); // "first" undefined undefined
//arguments ["first"]
Обьект arguments
создается в момент вызова функции.
arguments является "масивоподобным" обьектом (имеет числовой индекс и обладает свойством length
(и только).
Если нужно работать с arguments
, как с массивом (вызвать метод массива) объект arguments нужно превратить в массив. При этом по arguments
все так же можно итерировать циклом for
.
Для преобразования массивоподобного объекта в массив можно использовать абстракцию.
// функция которая преобразует обьект arguments в массив
function objectToArray(arrayLikeObject) {
var res = [];
for (var i = 0; i < arrayLikeObject.length; i += 1) {
res.push(arrayLikeObject[i]);
}
return res;
}
//рабочая функция
function f(first, second, third) {
var args = objectToArray(arguments); // обращаемся к функции arrayLikeObject для преобразования обьекта arguments в массив
console.log('undeinfed index', args.indexOf(undefined));
}
// Результат
f('mama', 'mila', undefined); // "undeinfed index" 2
Напишем функцию forEach
которая будет принимать аргументом массив и функию action
(пример с книги Eloquent JS). Функия forEach
вызывает для каждоного элемента массива функию action
, и передает туда i-тий аргумент массива. (дальше рассмотрим как реализовать аналогичную программу с использованием анонимной функции)
function forEach(array, action) {
for (var i = 0; i < array.length; i++) {
action(array[i]);
}
}
function log(val) {
console.log(val);
}
forEach(["Тили", "Мили", "Трямдия"], log)
Output:
"Тили"
"Мили"
"Трямдия"
Следует обратить внимание, что в параметр action
записывается значение второго аргумента, с которым вызывается forEach
(а именно log
), а арумент log
в свою очередь ссылается на функцию log
. Значит - в параметр action
записывается ссылка на функцию log
.
Теперь вызовем функцию log используя анонимную функцию (function first-class objects)
forEach(["Тили", "Мили", "Трямдия"], function (val) {
console.log(val, fff);
});
То есть мы обьявляем и передаем функцию на месте. Следует запомнить, что литеральная запись массива никак не отличается от литеральной записи функции.
Также фукнция может хранится в обьекте:
var ppp = {
log: function (val) {
console.log('THIS FUNC');
console.log(val);
}
};
И мы ссылаемся на ее следующим образом:
forEach(["Тили", "Мили", "Трямдия"], ppp.log);