|
@@ -0,0 +1,571 @@
|
|
|
+# Функции, области видимости
|
|
|
+
|
|
|
+## Trivia
|
|
|
+### Повторяющиеся действия.
|
|
|
+
|
|
|
+Как можно было заметить, компьютеры сильны именно в однотипных задачах, и делают простые задачи очень быстро. Связанные друг с другом однотипные задачи
|
|
|
+обычно
|
|
|
+повторяются в циклах (однотипные операции над массивами данных, статистические задачи, отрисовка повторяющихся данных на экране и так далее). Так же есть
|
|
|
+задачи *по требованию*, которые могут пригодится в любом месте кода. Например: `prompt`, `alert`, `Math.random` и прочие встроенные **функции**, которые
|
|
|
+являются *подпрограммами*, содержащими в себе программный код, вызываемый для решения определенной задачи. Я думаю понятно, что данные возможности
|
|
|
+*не являются* возможностями аппаратуры, а воплощены на программном уровне. Это значит, что подпрограммы являются *естественными* в компьютерах.
|
|
|
+
|
|
|
+### DRY
|
|
|
+
|
|
|
+**Don't repeat yourself**. Один из основопологающих принципов разработки. Суть в том, что в процессе программирования вы должны минимизировать
|
|
|
+повторяющиеся *части кода*, которые делают почти одинаковые задачи; так как копипаста в коде приводит к дублированию отладки, да и вообще некрасиво это
|
|
|
+:-)
|
|
|
+
|
|
|
+### KISS
|
|
|
+**Keep It Simple, Stupid**. Решайте задачи самым простым способом.
|
|
|
+> Отладка кода вдвое сложнее, чем его написание. Так что если вы пишете код настолько умно, насколько можете, то вы по определению недостаточно сообразительны, чтобы его отлаживать.
|
|
|
+> — *Brian W. Kernighan*.
|
|
|
+
|
|
|
+### DRY > KISS
|
|
|
+
|
|
|
+Зачастую эти принципы противоречат друг другу; уменьшение объема кода требует более мощных и сложнее отлаживаемых средств языка; однако в долгосрочной
|
|
|
+перспективе принцип **DRY** полезней, чем простота кода (**KISS**).
|
|
|
+
|
|
|
+### Пример
|
|
|
+
|
|
|
+```javascript
|
|
|
+var surname = prompt("Введите фамилию","")
|
|
|
+if (surname === null || surname === ""){
|
|
|
+ surname = "Иванов"
|
|
|
+}
|
|
|
+
|
|
|
+var name = prompt("Введите имя","") || "Иван"
|
|
|
+var fathername = prompt("Введите отчество","") || "Иванович"
|
|
|
+```
|
|
|
+
|
|
|
+Это наш пример, который спрашивает у пользователя ФИО ИЛИ берет эти параметры по умолчанию. Как видите, алгоритм ввода каждого из полей ФИО однотипен, и его
|
|
|
+неплохо было бы выделить в **функцию**. Ко всему прочему, несмотря на эквивалентность алгоритма, `surname` вводится кодом, отличающимся от
|
|
|
+ввода `name` и `fathername`, что усложняет модификацию и отладку кода.
|
|
|
+
|
|
|
+### Задание
|
|
|
+
|
|
|
+Порассуждаем о функциях, какие свойства должны быть у них, что бы они обеспечивали прозрачную работу в комбинации с другим кодом и не имели
|
|
|
+непредсказуемых побочных эффектов для кода, который их использует.
|
|
|
+
|
|
|
+# Ниже спойлер, имейте совесть :-D. Не омрачайте задание подглядыванием ответов.
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+## Функции
|
|
|
+
|
|
|
+**Функция** - подпрограмма, которая принимает определенные параметры при вызове, выполняет определенный код, и возвращает выполнение кода в место вызова,
|
|
|
+*опционально* (не обязательно) вернув результат работы в место вызова.
|
|
|
+
|
|
|
+### Свойства **функции**, которые сделали её такой полезной для написания программ
|
|
|
+
|
|
|
+#### Вызов.
|
|
|
+Функция может быть вызвана любое количество раз из разных несвязанных между собой мест кода, код функции выполнится, после чего выполнение кода
|
|
|
+ продолжится с места вызова:
|
|
|
+
|
|
|
+```javascript
|
|
|
+var callCounter = 0;
|
|
|
+function ourFunction()
|
|
|
+{
|
|
|
+ alert("Вызов № " + callCounter);
|
|
|
+ callCounter ++;
|
|
|
+}
|
|
|
+console.log(callCounter);
|
|
|
+ourFunction()
|
|
|
+console.log(callCounter);
|
|
|
+//тут еще может быть много кода, но мы можем опять воспользоваться функцией когда захотим:
|
|
|
+ourFunction()
|
|
|
+console.log(callCounter);
|
|
|
+```
|
|
|
+Для входа и выхода из функции используются `F11` и `Shift-F11` в **Developer Tools** при **пошаговой отладке**
|
|
|
+
|
|
|
+#### Область видимости.
|
|
|
+Так как функция не может "знать", из какого контекста она вызывается, то нет возможности знать заранее, совпадают ли имена
|
|
|
+переменных в функции и вне её. Таким образом вероятны *побочные эффекты* - непредсказуемые изменения переменных во внешнем коде, которые могут
|
|
|
+вызвать неправильную работу кода в целом. Побочные эффекты возникают при совпадении внутренних и внешних переменных:
|
|
|
+
|
|
|
+```javascript
|
|
|
+var surname = "Петров";
|
|
|
+function readSurname()
|
|
|
+{
|
|
|
+ surname = prompt("Введите фамилию","") //тут мы портим внешнюю переменную surname, и это нехорошо
|
|
|
+ if (surname === null || surname === ""){
|
|
|
+ surname = "Иванов"
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+console.log(surname);
|
|
|
+readSurname();
|
|
|
+console.log(surname);
|
|
|
+```
|
|
|
+
|
|
|
+Для решения этой проблемы используется концепция *области видимости* - **правильно** объявленная переменная
|
|
|
+в функции (через `var`) существует только в функции и создается каждый раз при вызове функции; внешние же переменные с таким же именем остаются
|
|
|
+нетронутыми
|
|
|
+
|
|
|
+```javascript
|
|
|
+var surname = "Петров";
|
|
|
+function readSurname()
|
|
|
+{
|
|
|
+ var surname = prompt("Введите фамилию","") // тут мы ничего не портим, эта переменная НЕ ЯВЛЯЕТСЯ внешней переменной surname
|
|
|
+ if (surname === null || surname === ""){
|
|
|
+ surname = "Иванов"
|
|
|
+ }
|
|
|
+}
|
|
|
+console.log(surname);
|
|
|
+readSurname();
|
|
|
+console.log(surname);
|
|
|
+```
|
|
|
+
|
|
|
+#### **Параметры**.
|
|
|
+Функция должна уметь получить те или иные данные для своего выполнения. Например встроенные функции `confirm`, `prompt`, `alert`.
|
|
|
+
|
|
|
+**Задание**: Каковы параметры и какой у них смысл в вышеуказанных встроенных функциях?
|
|
|
+
|
|
|
+```javascript
|
|
|
+var name = "Yohan"
|
|
|
+function greet(name){
|
|
|
+ alert("Hello, " + name);
|
|
|
+}
|
|
|
+
|
|
|
+greet(name)
|
|
|
+greet("John")
|
|
|
+greet("Paul")
|
|
|
+console.log(name)
|
|
|
+```
|
|
|
+
|
|
|
+#### **Возвращаемое значение**.
|
|
|
+Обратите внимание на то, что **функции** можно использовать как переменные в выражениях, однако не всегда это имеет смысл.
|
|
|
+Более того, **результату** функции нельзя присвоить значение, однако можно *прочесть* результат, вызвав функцию.
|
|
|
+
|
|
|
+**Задание**: какие из функций `prompt`, `confirm` и `alert` возвращают значения, а какие - нет?
|
|
|
+
|
|
|
+```javascript
|
|
|
+function random5(){
|
|
|
+ return Math.random()*5;
|
|
|
+}
|
|
|
+
|
|
|
+alert(random5());
|
|
|
+var someRandomValueFromZeroToFive = random5();
|
|
|
+```
|
|
|
+
|
|
|
+## Определение и выполнение функций
|
|
|
+
|
|
|
+Обратите внимание, что первый `alert` происходит ДО включения пошаговой отладки. Это говорит о том, что *определение функции* **НЕ** вызывает её.
|
|
|
+Код функции работает только после вызова, который происходит по `d()`. Для вызова надо указать в коде имя функции и скобки после имени (с параметрами
|
|
|
+или без оных)
|
|
|
+```javascript
|
|
|
+function d()
|
|
|
+{
|
|
|
+ debugger;
|
|
|
+}
|
|
|
+alert("before d");
|
|
|
+d()
|
|
|
+alert("after d");
|
|
|
+```
|
|
|
+
|
|
|
+Определение начинается с ключевого слова `function`, после которого идет имя функции и параметры в скобках через запятую. Далее идет блок кода функции
|
|
|
+в фигурных скобках. В отличие от `if`, `else` и циклов, фигурные скобки **обязательны**.
|
|
|
+
|
|
|
+При отладке и/или чтении чужого кода ищите вызовы функций. *Иногда* вызовы скрыты.
|
|
|
+
|
|
|
+### Именование функций
|
|
|
+
|
|
|
+Как и переменным, функциям нужно давать осмысленные названия. Только учтите, что переменные - *существительные* кода, а функции - *глаголы* кода.
|
|
|
+
|
|
|
+### Выполнение функций.
|
|
|
+
|
|
|
+Когда в коде упоминается имя функции со скобками и, возможно, параметрами происходят следующие действия:
|
|
|
+- вычисляются выражения в скобках. В функцию попадают уже *значения* выражений.
|
|
|
+- создается новая область видимости, в которую попадают параметры и их значения. Вам не нужно определять переменные для параметров.
|
|
|
+- начинается выполнение кода в фигурных скобках определения функции. Все переменные, определенные через `var` попадают в локальную область видимости функции, не перекрывающую внешнюю область видимости.
|
|
|
+- Код выполняется до выполнения `return` или окончания кода функции (закрывающей фигурной скобки). `return` прерывает выполнение функции, более того,
|
|
|
+ с помощью `return` происходит возврат значения функции, которое подставляется на место вызова функции. Таким образом функция ведет себя как
|
|
|
+ *переменная* для чтения. Если функция ничего не возвращает, то, на самом деле, она возвращает `undefined`
|
|
|
+
|
|
|
+```javascript
|
|
|
+function sqr(a){
|
|
|
+ alert("Вы передали:" + a);
|
|
|
+ return a*a;
|
|
|
+ alert("Этот код не выполнится");
|
|
|
+}
|
|
|
+
|
|
|
+var sqr1 = sqr(5)
|
|
|
+var otherVar = 2;
|
|
|
+alert("Сумма квадратов: " + (sqr1 + sqr(otherVar + otherVar)));
|
|
|
+```
|
|
|
+
|
|
|
+## Параметры функции и возвращаемое значение
|
|
|
+
|
|
|
+### Параметры (аргументы)
|
|
|
+
|
|
|
+Параметры функции перечисляются в скобках после имени через запятую. Параметры - это переменные области видимости функции, в которые попадают
|
|
|
+вычисленные значения, передаваемые при **вызове**. Таким образом функции получают данные из внешнего кода.
|
|
|
+
|
|
|
+В **Javascript** количество параметров при определении и при вызове может отличаться. Это не вызывает ошибок. В таком случае непереданные параметры равны
|
|
|
+`undefined`:
|
|
|
+```javascript
|
|
|
+debugger;
|
|
|
+function add(a,b)
|
|
|
+{
|
|
|
+ a = a || 0;
|
|
|
+ b = b || 0;
|
|
|
+ return a + b;
|
|
|
+}
|
|
|
+
|
|
|
+alert(add())
|
|
|
+alert(add(1));
|
|
|
+alert(add(2,3));
|
|
|
+```
|
|
|
+
|
|
|
+Если же параметров больше, чем указано в определении функции, то ошибки тоже не происходит. Для доступа к полям существует **псевдомассив**
|
|
|
+`arguments`, который всегда содержит актуальный набор параметров, переданных при вызове.
|
|
|
+```javascript
|
|
|
+debugger;
|
|
|
+function add(a,b)
|
|
|
+{
|
|
|
+ console.log(arguments)
|
|
|
+ a = a || 0;
|
|
|
+ b = b || 0;
|
|
|
+ return a + b;
|
|
|
+}
|
|
|
+
|
|
|
+alert(add(4,5,6))
|
|
|
+alert(add(4,5,6,7));
|
|
|
+
|
|
|
+prompt("Введите число", "0");
|
|
|
+prompt("Введите число");
|
|
|
+```
|
|
|
+
|
|
|
+**Задание**
|
|
|
+
|
|
|
+Используя перебор массива `arguments` циклом `for`, сделайте функцию, которая складывает любое количество параметров
|
|
|
+
|
|
|
+### Возвращаемое значение
|
|
|
+
|
|
|
+Для возврата значения используется `return`. У него три основных свойства:
|
|
|
+- Собственно возврат значения во внешний код. Выражение после `return` *вычисляется в контексте функции*:
|
|
|
+
|
|
|
+```javascript
|
|
|
+debugger;
|
|
|
+function add(a,b)
|
|
|
+{
|
|
|
+ return a + b;
|
|
|
+}
|
|
|
+alert(add(3,4))
|
|
|
+```
|
|
|
+
|
|
|
+после чего *значение* попадает в место, где функция была вызвана (в `alert`)
|
|
|
+- Прекращение выполнения функции
|
|
|
+- `return` без параметра возвращает *ничего*, т. е. `undefined`:
|
|
|
+
|
|
|
+```javascript
|
|
|
+debugger;
|
|
|
+function bigAndWeirdFunction()
|
|
|
+{
|
|
|
+ var somethingBad = Math.random() > 0.5;
|
|
|
+ if (somethingBad){
|
|
|
+ alert("Something bad happens");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ alert("All OK!");
|
|
|
+}
|
|
|
+bigAndWeirdFunction();
|
|
|
+bigAndWeirdFunction();
|
|
|
+bigAndWeirdFunction();
|
|
|
+```
|
|
|
+
|
|
|
+### `console.log` и `return`
|
|
|
+
|
|
|
+При отладке вы видите в одной консоли *вычисленное значение выражения* (например `2 + 2` или `prompt("Введите число")`) и вывод `console.log`.
|
|
|
+`console.log` *просто выводит текст* в консоль, как `document.write` - в окно браузера, далее вы с этим ничего не можете сделать (почти).
|
|
|
+**Выражение** же может быть вставлено в код и являться частью другого выражения:
|
|
|
+
|
|
|
+```javascript
|
|
|
+2 + 2
|
|
|
+var a = 2 + 2
|
|
|
+prompt("Введите число");
|
|
|
+var num = prompt("Введите число");
|
|
|
+
|
|
|
+var b;
|
|
|
+ b = console.log(a); //неработает, метод log объекта console возвращает undefined, т. е. ничего
|
|
|
+ b = a; //работает
|
|
|
+
|
|
|
+function myLowerCase(str)
|
|
|
+{
|
|
|
+ console.log(str.toLowerCase()); //это просто пишет текст в консоли.
|
|
|
+}
|
|
|
+
|
|
|
+function rightUpperCase(str)
|
|
|
+{
|
|
|
+ return str.toUpperCase(); //это работает правильно
|
|
|
+}
|
|
|
+
|
|
|
+var lowerCase = myLowerCase("AbCdEf") //не работает.
|
|
|
+var upperCase = rightUpperCase("AbCdEf") //работает
|
|
|
+```
|
|
|
+
|
|
|
+Что бы отличить результат выражения от вывода console.log, отметьте что возле значения выражения есть знак `<`.
|
|
|
+
|
|
|
+## Область видимости
|
|
|
+
|
|
|
+Как было указано выше, переменные, объявленные с `var` внутри функции, являются незаметными для окружающего кода и перекрывают совпадающие переменные
|
|
|
+внутри функции, оставляя невредимыми внешние переменные:
|
|
|
+
|
|
|
+```javascript
|
|
|
+var a = 5;
|
|
|
+
|
|
|
+alert("global a: " + a);
|
|
|
+function someFunctionWithA(){
|
|
|
+ var a = "string";
|
|
|
+ alert("function scope a: " + a);
|
|
|
+}
|
|
|
+
|
|
|
+alert("global a after function declaration" + a);
|
|
|
+someFunctionWithA()
|
|
|
+alert("global a after function execution" + a);
|
|
|
+```
|
|
|
+
|
|
|
+Область видимости создается **каждый раз** при **вызове** функции:
|
|
|
+
|
|
|
+```javascript
|
|
|
+
|
|
|
+debugger;
|
|
|
+function add(a,b)
|
|
|
+{
|
|
|
+ var result = a + b;
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+add(1,2)
|
|
|
+add(5,6)
|
|
|
+```
|
|
|
+
|
|
|
+Как видите, переменные `a`,`b` и `result` каждый раз имеют разные значения. При вызове область видимости создается, по выходу из функции - удаляется
|
|
|
+(*не всегда*).
|
|
|
+
|
|
|
+### Глобальная область видимости
|
|
|
+
|
|
|
+Если переменная создается **без** `var` в *любом* месте кода, в том числе в функции, она является глобальной, т. е. видимой везде.
|
|
|
+
|
|
|
+```javascript
|
|
|
+debugger;
|
|
|
+function add(a,b)
|
|
|
+{
|
|
|
+ result = a + b;
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+result = add(1,2)
|
|
|
+alert(result);
|
|
|
+add(5,6)
|
|
|
+alert(result);
|
|
|
+```
|
|
|
+
|
|
|
+Как видно в примере выше, мы не можем расчитывать на целостность переменной `result`, пользуясь функцией `add`. Использование глобальных переменных
|
|
|
+в большинстве случаев неоправдано; они нужны в-основном только для каких-то общих данных для чтения. Например `Math.PI` является глобальной переменной,
|
|
|
+доступной только на чтение; то есть *константой*. Ваши же переменные будут доступны и на запись, будьте аккуратны используя их.
|
|
|
+
|
|
|
+**Общее правило для новичка**: всегда ставьте `var`.
|
|
|
+
|
|
|
+
|
|
|
+### Вложенные функции и их области видимости
|
|
|
+
|
|
|
+```javascript
|
|
|
+var a = "0";
|
|
|
+var b = "0";
|
|
|
+var c = "0";
|
|
|
+
|
|
|
+function level1(){
|
|
|
+ var b = "1";
|
|
|
+ var c = "1";
|
|
|
+
|
|
|
+ function level2(){
|
|
|
+ var c = "2";
|
|
|
+ console.log("Level 2 scope: a: " + a + " b: " + b + " c: " + c);
|
|
|
+ }
|
|
|
+ level2();
|
|
|
+ console.log("Level 1 scope: a: " + a + " b: " + b + " c: " + c);
|
|
|
+}
|
|
|
+
|
|
|
+level1();
|
|
|
+console.log("Level 0 scope: a: " + a + " b: " + b + " c: " + c);
|
|
|
+```
|
|
|
+Проанализируйте вывод кода выше. Самая вложенная функция `level2` видит переменные своей области видимости (`c`), потом ищет значение на уровень
|
|
|
+выше (для переменной `b`), и на уровень еще выше (для `a`). Промежуточная функция `level1` *ничего* не знает о переменных в `level2`, но видит свою
|
|
|
+область видимости и глобальную. Глобальная же имеет свои переменные `a`, `b`, `c` в первозданном виде.
|
|
|
+
|
|
|
+```javascript
|
|
|
+var a = "0";
|
|
|
+var b = "0";
|
|
|
+var c = "0";
|
|
|
+
|
|
|
+function level1(){
|
|
|
+ var b = "1";
|
|
|
+ var c = "1";
|
|
|
+ var d = "1";
|
|
|
+
|
|
|
+ function level2(){
|
|
|
+ var c = "2";
|
|
|
+ var e = "2";
|
|
|
+ console.log("Level 2 scope: a: " + a + " b: " + b + " c: " + c + " d: " + d + " e: " + e);
|
|
|
+ d = "2";
|
|
|
+ }
|
|
|
+ console.log("Level 1 before level2, scope: a: " + a + " b: " + b + " c: " + c + " d: " + d + " e: " + e);
|
|
|
+ level2();
|
|
|
+ console.log("Level 1 after level2, scope: a: " + a + " b: " + b + " c: " + c + " d: " + d + " e: " + e);
|
|
|
+}
|
|
|
+
|
|
|
+level1();
|
|
|
+console.log("Level 0 scope: a: " + a + " b: " + b + " c: " + c + " d: " + d + " e: " + e);
|
|
|
+```
|
|
|
+
|
|
|
+Данный пример иллюстрирует отсутствие переменных `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 numberSort(a, b){
|
|
|
+ return a > b ? 1 : -1;
|
|
|
+}
|
|
|
+arrayOfNumbers.sort(numberSort); //сортировка по числовому значению
|
|
|
+```
|
|
|
+
|
|
|
+Первый `sort` выше сортирует, используя знаки `<` для элементов массива, интерпретируя элементы как строки;
|
|
|
+
|
|
|
+Второй `sort` принимает в качестве параметра функцию, которая вызывается внутри `sort` для некой пары сортируемых элементов. Пара выбирается согласно логике
|
|
|
+алгоритма сортировки; выбор же, кто из этих двух элементов больше, а кто - меньше, возлагается на переданную функцию `numberSort`, которая должна вернуть
|
|
|
+1 если `а` считается больше `b` и -1 в обратном случае. В случае равенства `a` и `b` - возвращается 0.
|
|
|
+
|
|
|
+Таким же образом мы можем отсортировать по тому или иному критерию массив объектов (ассоциативных массивов), например:
|
|
|
+
|
|
|
+```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 когда это событие произошло.
|
|
|
+
|
|
|
+```javascript
|
|
|
+console.log("Начал");
|
|
|
+setTimeout(function(){
|
|
|
+ console.log("Отложил на 5 сек");
|
|
|
+}, 5000);
|
|
|
+console.log("Закончил");
|
|
|
+```
|
|
|
+ В этом примере, вместо того, что бы засекать время и постоянно в цикле проверять, прошел ли нужный промежуток времени (5 секунд), используется
|
|
|
+ встроенная функция setTimeout, которая запускает ваш код через определенное время. Код предоставляется в форме функции, время вторым параметром
|
|
|
+ в миллисекундах.
|
|
|
+
|
|
|
+- Функции используются для создания обособленной области видимости, что бы не нарушать окружающее пространство имен:
|
|
|
+
|
|
|
+```javascript
|
|
|
+(function(){
|
|
|
+ var a = 5;
|
|
|
+ var b = "100500";
|
|
|
+})()
|
|
|
+```
|
|
|
+в данном примере создается функция и тут же вызывается. Функция не сохраняется ни в какой из переменных, а значит вы не сможете её вызвать более
|
|
|
+чем один раз. Единственная цель такой функции (**Self-Invoked Function**) - создать свою собственную область видимости, в которой можно оперировать
|
|
|
+любыми именами переменных не опасаясь побочных эффектов и влияния на переменные окружающего кода. Просто блок кода со своими именами.
|
|
|
+
|