|
@@ -416,4 +416,128 @@ console.log("Level 0 scope: a: " + a + " b: " + b + " c: " + c + " d: " + d + "
|
|
|
Данный пример иллюстрирует отсутствие переменных `e` в глобальной области видимости и `level1`, переменной `d` - в глобальной области видимости. Переменная
|
|
|
`d` попадает из `level1` в `level2`.
|
|
|
|
|
|
-##
|
|
|
+## Функции высшего порядка.
|
|
|
+
|
|
|
+### Функция как тип данных.
|
|
|
+
|
|
|
+Функции в **JS** являются *типом данных*, наряду с числами и строками. Определение функции является выражением и вычисляется как значение типа данных
|
|
|
+`function`:
|
|
|
+
|
|
|
+```javascript
|
|
|
+function a(){
|
|
|
+}
|
|
|
+alert(typeof a);
|
|
|
+```
|
|
|
+
|
|
|
+Набор операций с функциями невелик, в отличие от строк их нельзя конкатенировать, нельзя складывать и умножать как числа; однако их можно присваивать
|
|
|
+переменным и вызывать. **JS** позволяет создавать функции без названия:
|
|
|
+
|
|
|
+```javascript
|
|
|
+a();
|
|
|
+function a(){
|
|
|
+ console.log('declared func');
|
|
|
+}
|
|
|
+
|
|
|
+someFuncVariable()
|
|
|
+var someFuncVariable = function (){
|
|
|
+ console.log('anon func');
|
|
|
+}
|
|
|
+
|
|
|
+someFuncVariable()
|
|
|
+
|
|
|
+var b = a;
|
|
|
+a = null;
|
|
|
+a()
|
|
|
+a = b
|
|
|
+a()
|
|
|
+```
|
|
|
+
|
|
|
+### Функции высшего порядка
|
|
|
+
|
|
|
+**Функциями высшего порядка** называют функции, которые оперируют другими функциями - принимают их в качестве параметров или возвращают как результат
|
|
|
+выполнения. Такой подход позволяет произвести *инъекцию своего кода*. Например, все реализации алгоритма сортировки сравнивают разные сортируемые элементы,
|
|
|
+при этом для работы алгоритма *вовсе не обязательно* знать структуру сортируемых данных; достаточно просто знать, какой элемент из двух *больше* или *меньше*.
|
|
|
+
|
|
|
+Функция, передаваемая в качестве параметра другой функции для последующего вызова называется `callback`.
|
|
|
+
|
|
|
+```javascript
|
|
|
+var arrayOfNumbers = [4,18,10,2,-1,100, 0, 0.5];
|
|
|
+arrayOfNumbers.sort(); //сортирует, используя обычное сравнение `<` и `>`
|
|
|
+
|
|
|
+function absSort(a, b){
|
|
|
+ return Math.abs(a) > Math.abs(b) ? 1 : -1;
|
|
|
+}
|
|
|
+arrayOfNumbers.sort(absSort); //сортировка по абсолютному значению
|
|
|
+```
|
|
|
+
|
|
|
+Первый `sort` выше сортирует, используя знаки `<` для элементов массива;
|
|
|
+
|
|
|
+Второй `sort` принимает в качестве параметра функцию, которая вызывается внутри `sort` для некой пары сортируемых элементов. Пара выбирается согласно логике
|
|
|
+алгоритма сортировки; выбор же, кто из этих двух элементов больше, а кто - меньше, возлагается на переданную функцию `absSort`, которая должна вернуть
|
|
|
+1 если `а` считается больше `b` и -1 в обратном случае. В случае равенства `a` и `b` - возвращается 0.
|
|
|
+
|
|
|
+Функция `absSort` сравнивает числа по *абсолютному значению*, т. е. по модулю. Таким образом самым маленьким числом в массиве является 0, потом 0.5, -1 и
|
|
|
+так далее.
|
|
|
+
|
|
|
+Таким же образом мы можем отсортировать по тому или иному критерию массив объектов (ассоциативных массивов), например:
|
|
|
+
|
|
|
+```javascript
|
|
|
+var persons = [
|
|
|
+ {name: "Иван", age: 17},
|
|
|
+ {name: "Мария", age: 35},
|
|
|
+ {name: "Алексей", age: 73},
|
|
|
+ {name: "Яков", age: 12},
|
|
|
+]
|
|
|
+persons.sort(function(a,b){ //сортируем по возрасту
|
|
|
+ if (a.age > b.age){
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+});
|
|
|
+
|
|
|
+persons.sort(function(a,b){ //сортируем по имени
|
|
|
+ if (a.name > b.name){
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ return -1;
|
|
|
+});
|
|
|
+```
|
|
|
+
|
|
|
+Рассмотрим пример:
|
|
|
+
|
|
|
+```javascript
|
|
|
+function intPrompt(message, defaultValue)
|
|
|
+{
|
|
|
+ do {
|
|
|
+ var value = prompt(message, defaultValue);
|
|
|
+ } while(isNaN(+value) || !Number.isInteger(+value) && value !== null);
|
|
|
+ return value;
|
|
|
+}
|
|
|
+
|
|
|
+function validatedPrompt(message, defaultValue, validator)
|
|
|
+{
|
|
|
+ do {
|
|
|
+ var value = prompt(message, defaultValue);
|
|
|
+ } while(!validator(value) && value !== null);
|
|
|
+ return value;
|
|
|
+}
|
|
|
+debugger;
|
|
|
+alert(validatedPrompt("number", "", function(value) {
|
|
|
+ return !isNaN(+value) && Number.isInteger(+value)
|
|
|
+}))
|
|
|
+
|
|
|
+alert(validatedPrompt("камень-нжнцы-бмг", "", function(value) {
|
|
|
+ return ["камень", "ножницы", "бумага"].indexOf(value.toLowerCase()) > -1;
|
|
|
+}))
|
|
|
+```
|
|
|
+
|
|
|
+## Для чего используются функции.
|
|
|
+
|
|
|
+- Для избавления повторяющихся кусков кода. **DRY**
|
|
|
+- Для структуризации и задания имени какой-либо последовательности операций. Например зачастую в начале работы кода запускают однократно функцию
|
|
|
+ `init` (имя приведено для примера), которая выполняется *один* раз, т. е. не уменьшает объем кода. Однако, таким образом, все действия, которые
|
|
|
+ относятся к подготовке программного окружения, заносятся в отдельный блок кода, что более наглядно
|
|
|
+- Функции обратного вызова используются для внедрения кода, как в случае с `sort` и `validatedPrompt`
|
|
|
+- Функции обратного вызова используются для того, что бы отказаться от опроса (poll) и перейти к событийной архитектуре (push), т. е. вместо
|
|
|
+ постоянной проверки произошло то или иное событие или нет - происходит вызов callback когда это событие произошло.
|
|
|
+
|