Объект Function

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

Синтаксис

new Function ([arg1[, arg2[, ... argN]],] functionBody)

Параметры

arg1, arg2, ... argN

Имена параметров для создаваемой функции. Каждый аргумент должен быть строкой, которая является корректным идентификатором javascript или списком таких строк, разделенных запятой. Например: "x", "theValue" или "a,b".
functionBody
javascript-код тела функции

Описание, комментарии, примеры

Каждая функция в JavaScriptт является объектом класса Function.

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

Вызов конструктора Function как функции работает так же, как вызов с new. Иначе говоря, оператор new при вызове Function необязателен.

Пример создания функции

var multiply = new Function("x", "y", "return x * y")
// или так:
var multiply = new Function("x,y", "return x * y")
var theAnswer = multiply(7, 6);

Свойства

length
Специфицирует количество аргументов, ожидаемое функцией.

Методы

apply
Даёт возможность применять метод другого объекта в контексте вызывающего объекта.
bind
создаёт новую функцию, которая при вызове устанавливает в качестве контекста выполнения this предоставленное значение.
call
Позволяет вызывать (выполнять) метод другого объекта в контексте вызывающего объекта

length

Свойство length определяет количество аргументов, ожидаемых функцией.

Комментарии

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

Для получения аргументов, реально переданных функции, внутри тела функции можно использовать псевдо-массив arguments и его свойство length

.

apply

Даёт возможность применить метод другого объекта в контексте вызывающего объекта.

Синтаксис

function.apply(thisArg[, argsArray]);

Параметры

thisArg
Задает значение this внутри функции.
Если thisArg - null или undefined, то это будет глобальный объект.
В ином случае, this будет равно Object(thisArg) (то есть thisArg, если thisArg уже объект, или String, Boolean или Number, если thisArg - примитивное значение соответствующего типа). Таким образом, при выполнении функции всегда соблюдается условие typeof this == 'object'.
argsArray
Массив аргументов, с которыми будет вызвана функция, или null/undefined для вызова без аргументов.

Комментарии

Любую функцию в JavaScript можно вызвать в контексте любого объекта.

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

Метод apply очень похож на call, за исключением передачи аргументов. В apply используется массив аргументов вместо списка именованных параметров.

Используя apply, вы можете использовать литеральное объявление массива, например:

fun.apply(this, [name, value])

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

bind

Метод bind() создаёт новую функцию, которая при вызове устанавливает в качестве контекста выполнения this предоставленное значение. В метод также передаётся набор аргументов, которые будут установлены перед переданными в привязанную функцию аргументами при её вызове.

Синтаксис

function.bind(thisArg[, arg1[, arg2[, ...]]])

Параметры

thisArg
Значение, передаваемое в качестве this в целевую функцию при вызове привязанной функции. Значение игнорируется, если привязанная функция конструируется с помощью оператора new.
arg1, arg2 ..
Аргументы, с которыми будет вызвана функция.

Примеры

let obj = {  // инициализируем переменную, содержащую объект
    a: 100,
    b: 200
};

// функция возвращает сумму трех значений
let func = function( c ) { return this.a + this.b + c };

// переменная содержит новую функцию, которая вызывается как метод объекта
let newFunc = func.bind( obj, 300 );

newFunc(); // возвращаемое значение 600

В следующем примере мы создадим новую функцию путём фиксирования аргументов существующей (частичное применение), этот прием в функциональном программировании называется каррингом (currying):

// функция воз­вра­ща­ет произведение 2 ар­гу­мен­тов
let multiply = function( a,b ) { return a * b }; 

// соз­даем но­вую функ­цию, по­доб­ную multiply, но с контекстом равным null и первым аргументом равным 3
let triple = multiply.bind( null, 3 );

// но­вая функ­ция при­ни­ма­ет один ар­гу­мент
triple(2) // 6 (первый ар­гу­мент свя­зан со зна­че­ни­ем 3, а значение 2 пе­ре­да­ет­ся в качестве второго аргумента)
triple(3) // 9 (первый ар­гу­мент свя­зан со зна­че­ни­ем 3, а значение 3 пе­ре­да­ет­ся в качестве второго аргумента)
triple(4) // 12 (первый ар­гу­мент свя­зан со зна­че­ни­ем 3, а значение 4 пе­ре­да­ет­ся в качестве второго аргумента)

call

Позволяет вызывать (выполнять) метод другого объекта в контексте данного (вызывающего) объекта.

Синтаксис

function.call(thisArg[, arg1[, arg2[, ...]]])

Параметры

thisArg
Задает значение this внутри функции. Если thisArg - null или undefined, то это будет глобальный объект. В ином случае, this будет равно Object(thisArg) (то есть thisArg, если thisArg уже объект, или String, Boolean или Number, если thisArg - примитивное значение соответствующего типа). Таким образом, при выполнении функции всегда соблюдается условие typeof this == 'object'.
arg1, arg2 ..
Аргументы, с которыми будет вызвана функция.

Комментарии

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

Примеры

Вызов sayName в контексте разных объектов

var Animal1 = {name: 'Cat'}
var Animal2 = {name: 'Dog'}
 
function sayName() {
    // this — ссылка на объект, в контексте которого вызвана функция
    alert(this.name);
}
 
sayName.call(Animal1) // выдаст сообщение "Cat"
sayName.call(Animal2) // выдаст сообщение "Dog"


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

var Animal1 = {
    name: 'Cat',
    sayName: function() {
        alert(this.name);
    }
};
 
var Animal2 = {name: 'Dog'};
 
Animal1.sayName() // выдаст сообщение "Cat"
Animal1.sayName.call(Animal2) // выдаст сообщение "Dog"


Помимо смены контекста вызова, метод call может передавать в функцию аргументы:

var obj = {attr: 10};
 
function sum(a, b) {
    alert(this.attr + a + b);
}
 
sum.call(obj, 5, 2) // выдаст сообщение с результатом "17"


var str = ''; 
function callMe(arg1, arg2){
    var s = "";

    s += "this value: " + this;
    s += "\n";
    for (i in callMe.arguments) {
        s += "arguments: " + callMe.arguments[i];
        s += "\n";
    }
    return s;
}

str += "Original function: \n";
str += callMe(1, 2) + '\n';

str += "Function called with call:\n";
str += callMe.call(3, 4, 5);
alert (str); /*
Output: 
  Original function: 
  this value: [object Window]
  arguments: 1
  arguments: 2

  Function called with call: 
  this value: 3
  arguments: 4
  arguments: 5 */

arguments

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

Описание, комментарии, примеры

Локальная переменная arguments доступна внутри функций.

Вы можете обращаться к аргументу по номеру, начиная от 0. При этом arguments содержит не объявленные, а реально переданные аргументы.

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

function func(a,b) {
  alert(arguments[0] + '\n '+
	arguments[1] + '\n '+
	arguments[2])
}
 
func(1,2,3)

Кроме цифровых индексов, у arguments есть свойство length, такое же как у массива.

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

function sum() {
  var s = 0;
  for(var i=0; i < arguments.length; i++) s += arguments[i];
  return s;
}
alert ( sum (1,2,3,4,5,6,7,8,9) );

Несмотря на доступ по индексу и наличие свойства length, arguments не является массивом, т.е не принадлежит типу Array.

Поэтому для arguments нельзя напрямую вызвать методы этого класса:

arguments.pop() // ошибка !

Можно, однако, вызвать методы Array через apply/call:

var args = Array.prototype.slice.call(arguments)

Ссылка на функцию arguments.callee

Кроме аргументов, arguments содержит ссылку на выполняющуюся функцию.

Ее можно использовать для задания и чтения статических свойств.

В следующем примере для этого используется статическое свойство called.
Пример: подсчет количества выполнений

function func() {
   arguments.callee.called++
}
func.called = 0;
 
func()
func()
alert(func.called) // 2

Значения по умолчанию

Если при вызове функции аргумент не был указан, то его значением становится undefined.

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

ex_1:     ex_2:  

function setBgColor(selector, color = 'green') {
  const el = document.querySelector(selector);
  el.style.backgroundColor = color;
}
setBgColor('#ex_1');
setBgColor('#ex_2', '#00aabb');

При вызове функции с одним аргументом, второму параметру будет автоматически присвоено строка 'green'.

Работу параметра по умолчанию можно представить так:

function setBgColor(selector,color) {
  const el = document.querySelector(selector);
  color = color === undefined ? 'green' : color
  el.style.backgroundColor = color;
}
setBgColor('#ex_2');
setBgColor('#ex_1', '#00aabb');

Остаточные параметры (...)

Остаточные параметры могут быть обозначены через три точки .... Буквально это значит: «собери оставшиеся параметры и положи их в массив».

Например, соберём все аргументы в массив args:

function sumAll(...args) { // args — имя массива
  let sum = 0;
  for (let arg of args) sum += arg;
  return sum;
}

alert( sumAll(1) ); // 1
alert( sumAll(1, 2) ); // 3
alert( sumAll(1, 2, 3) ); // 6
Можно положить первые несколько параметров в переменные, а остальные – собрать в массив. В примере ниже первые два аргумента функции станут именем и фамилией, а третий и последующие превратятся в массив titles:
function showName(firstName, lastName, ...titles) {
  alert( firstName + ' ' + lastName ); // Юлий Цезарь

  // Оставшиеся параметры пойдут в массив titles = ["Консул", "Император"]
  alert( titles[0] ); // Консул
  alert( titles[1] ); // Император
  alert( titles.length ); // 2
}

showName("Юлий", "Цезарь", "Консул", "Император");

Остаточные параметры должны располагаться в конце

Оператор расширения

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

Давайте разберем, что это означает и чем нам может пригодится.

Пример 1 — вставка массивов в массив

В приведенном примере мы не используем оператор расширения и хотим поместить субмассив в начальный массив.

let mid = [3, 4];
let arr = [1, 2, mid, 5, 6];

Мы создали массив mid. Затем мы создали новый массив, который поместили в массив mid. Если выполнить этот код, мы получим:

[
1, 2, [3, 4], 5, 6]

И это не то, что мы хотели получить. Мы хотели получить цифры от 1 до 6. И тут нам поможет оператор расширения!

const mid = [3, 4];
let arr = [1, 2, ...mid, 5, 6]; alert(arr);

А вот в этом случае мы как раз и получим [1, 2, 3, 4, 5, 6].

Создавая массив arr и используя … при вставке субмассива, наш массив mid расширяется. Это расширение означает, что каждый элемент массива mid помещается внутрь arr.

Пример 2

let arr1 = [1, -2, 3, 4];
let arr2 = [8, 3, -8, 1];

alert( Math.max(1, ...arr1, 2, ...arr2, 25) ); // 25

let str = "Привет";  alert( [...str] ); // П,р,и,в,е,т

Функции-стрелки

Существует ещё более простой и краткий синтаксис для создания функций, который часто лучше, чем синтаксис Function Expression.

Он называется «функции-стрелки» или «стрелочные функции» (arrow functions), т.к. выглядит следующим образом:

let func = (arg1, arg2, ...argN) => expression

…Такой код создаёт функцию func с аргументами arg1..argN и вычисляет expression с правой стороны с их использованием, возвращая результат.

Другими словами, это более короткий вариант такой записи:

let func = function(arg1, arg2, ...argN) {
  return expression;
};

Давайте взглянем на конкретный пример:

let sum = (a, b) => a + b;

/* Более короткая форма для:

let sum = function(a, b) {
  return a + b;
};
*/

alert( sum(1, 2) ); // 3

То есть, (a, b) => a + b задаёт функцию с двумя аргументами a и b, которая при запуске вычисляет выражение справа a + b и возвращает его результат.

Функции-стрелки могут быть использованы так же, как и Function Expression.

Например, для динамического создания функции:

let age = prompt("Сколько Вам лет?", 18);

let welcome = (age < 18) ?
  () => alert('Привет') :
  () => alert("Здравствуйте!");

welcome(); // теперь всё в порядке

Поначалу функции-стрелки могут показаться необычными и трудночитаемыми, но это быстро пройдёт, как только глаза привыкнут к этим конструкциям.

Они очень удобны для простых однострочных действий, когда лень писать много букв.

Стрелочные функции – это не просто «сокращение», чтобы меньше писать. У них есть ряд других полезных особенностей.

При написании JavaScript-кода часто возникают ситуации, когда нам нужно написать небольшую функцию, которая будет выполнена где-то ещё.

Например:

Это очень в духе JavaScript – создать функцию и передать её куда-нибудь.

И в таких функциях мы обычно не хотим выходить из текущего контекста. Здесь как раз и полезны стрелочные функци

Многострочные стрелочные функции

В примерах выше аргументы использовались слева от =>, а справа вычислялось выражение с их значениями.

Порой нам нужно что-то посложнее, например, выполнить несколько инструкций. Это также возможно, нужно лишь заключить инструкции в фигурные скобки. И использовать return внутри них, как в обычной функции.

Например:

let sum = (a, b) => {  // фигурная скобка, открывающая тело многострочной функции
  let result = a + b;
  return result; // при фигурных скобках для возврата значения нужно явно вызвать return
};

alert( sum(1, 2) ); // 3

Стрелочные функции:

  1. Без фигурных скобок: (...args) => expression – правая сторона выражение: функция выполняет его и возвращает результат.
  2. С фигурными скобками: (...args) => { body } – скобки позволяют нам писать многострочные инструкции внутри функции, но при этом необходимо указывать директиву return, чтобы вернуть какое-либо значение.
  3. Не имеют this.
  4. Не имеют arguments.
  5. Не могут быть вызваны с new.