Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Основы программирования на JavaScript. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
12.08.2026
Размер:
1 Мб
Скачать

5.Найдите в массиве var arr = [ … ] максимальный и минимальный элементы. Массив возьмите по варианту из табл. 4.

6.С помощью методов массива split, join, push, pop, shift, unshift, splice превратите исходную строку в новую строку по варианту из табл. 6.

Таблица 6. Варианты задания

Исходная

'I don’t

 

'I don’t

'I don’t

'I don’t

 

'I don’t

строка

 

 

like

 

like

like

like

 

like

Новая

 

 

Pascal'

 

C++'

Python'

Delphi'

 

Assembler'

строка

 

 

 

 

 

 

 

 

 

'I love

1, 17

 

3, 19

5, 11

7, 13

 

9, 15

JavaScript'

 

 

 

 

 

 

 

 

 

'JavaScript

2, 18

 

4, 20

6, 12

8, 14

 

10, 16

forever'

 

 

 

 

 

 

 

 

 

2.3. Лабораторная

работа

и практическое

занятие № 3.

Функции

 

 

 

 

 

 

 

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

Объявление функции

Для создания функций используется объявление функции. Вначале идет ключевое слово function, после него имя функции,

затем список параметров в круглых скобках через запятую (в следующем примере он пустой) и, наконец, код функции, также называемый «телом функции», внутри фигурных скобок.

function имя(параметры) {

...тело...

}

Вызов функции осуществляется по имени: function showMessage() {

console.log ('Всем привет!');

}

showMessage();

Параметры

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

31

В следующем примере функции передаются два парамет-

ра: from и text.

function showMessage(from, text) {

// аргументы: from, text console.log (from + ',' + text);

}

showMessage('Аня', 'привет!'); // (*) // Аня, привет!

showMessage('Аня', 'как дела?'); // (**) // Аня, как дела?

Когда функция вызывается в строках (*) и (**), переданные значения копируются в локальные переменные from и text. Затем они используются в теле функции.

Параметры по умолчанию

Если параметр не указан, то его значением становится undefined. Например, функция showMessage (from, text), рассмотренная

выше, может быть вызвана с одним аргументом: showMessage('Аня');

Это не будет ошибкой. Такой вызов приведет к выводу «Аня, undefined». В вызове не указан параметр text, поэтому предполагается,

что text === undefined.

Если мы хотим задать параметру text значение по умолчанию, нужно указать его после «=».

function showMessage(from, text = 'текст не добавлен') {

console.log (from + ',' + text);

}

showMessage('Аня'); // Аня, текст не добавлен

Теперь, если параметр text не указан, его значением будет «текст не добавлен».

В данном случае «текст не добавлен» – это строка, но на ее месте могло бы быть и более сложное выражение, которое бы вычислялось и присваивалось при отсутствии параметра, как в следующем примере:

function showMessage(from, text = anotherFunction()) {

//anotherFunction() выполнится,

//если только не передан text;

//в результате получится значение text

}

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

32

В примере выше anotherFunction() будет вызываться каждый раз, когда showMessage() вызывается без параметра text.

Возвращение значения

Функция может вернуть результат, который будет передан в вызвавший ее код. Простейшим примером может служить функция сложения двух чисел.

function sum(a, b) { return a + b;

}

let result = sum(1, 2); console.log(result); // 3

Директива return может находиться в любом месте тела функции. Как только выполнение доходит до этого места, функция останавливается и значение возвращается в вызвавший ее код (присваивается переменной result выше).

Вызовов return может быть несколько. function checkAge(age) {

if (age > 18) { return true;

}else {

return confirm('А родители разрешили?');

}

}

let age = prompt('Сколько вам лет?', 18); if ( checkAge(age) ) {

console.log('Доступ получен'); } else {

console.log('Доступ закрыт');

}

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

function showMovie(age) { if ( !checkAge(age) ) {

return;

}

console.log ('Вам показывается кино'); // (*) // ...

}

В коде выше, если checkAge(age) вернет false, showMovie не выполнит console.log.

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

function doNothing() { /* пусто */ } console.log(doNothing() === undefined); // true

33

Пустой return аналогичен return undefined: function doNothing() {

return;

}

console.log(doNothing() === undefined); // true

Длинное выражение в return можно разместить на нескольких отдельных строках. Чтобы возвращаемое выражение занимало несколько строк, нужно начать его на той же строке, что и return, или поставить там открывающую скобку:

return (

some + long + expression + or +

whatever * f(a) + f(b)

)

Выбор имени функции

Функция – это действие, поэтому имя функции обычно является глаголом. Оно должно быть простым, точным и описывать действие функции, чтобы программист, который будет читать код, получил верное представление о том, что делает функция.

Как правило, используются глагольные префиксы, обозначающие общий характер действия, после которых следует уточнение. Обычно в командах разработчиков действуют соглашения, касающиеся значений этих префиксов.

Например, функции, начинающиеся со слова:

«show...» – что-то показывают;

«get…» – возвращают значение;

«calc…» – что-то вычисляют;

«create…» – что-то создают;

«check…» – что-то проверяют и возвращают логическое зна-

чение.

Примеры таких имен представлены ниже. showMessage(..)

//показывает сообщение getAge(..)

//возвращает возраст (в каком-либо значении) calcSum(..)

//вычисляет сумму и возвращает результат createForm(..)

//создает форму (и обычно возвращает ее) checkPermission(..)

//проверяет доступ, возвращая true или false

34

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

Функция в роли комментария

Функции должны быть короткими и делать только что-то одно. Если это что-то большое, имеет смысл разбить функцию на несколько меньших. Иногда следовать этому правилу непросто, но это определенно хорошее правило.

Небольшие функции не только облегчают тестирование и отладку. Само существование таких функций играет роль хороших комментариев. Например, можно сравнить два варианта функции showPrimes(n). Каждый из них выводит простые числа от 1 до n [6].

Первый вариант использует метку nextPrime. function showPrimes(n) {

nextPrime: for (let i = 2; i < n; i++) { for (let j = 2; j < i; j++) {

if (i % j == 0) continue nextPrime;

}

console.log(i); // простое число

}

}

Второй вариант использует дополнительную функцию isPrime(n) для проверки чисел на простоту:

function showPrimes(n) {

for (let i = 2; i < n; i++) { if (!isPrime(i)) continue;

console.log(i); // простое число

}

}

function isPrime(n) {

for (let i = 2; i < n; i++) { if ( n % i == 0) return false;

}

return true;

}

Второй вариант легче для понимания. Вместо части кода мы видим название действия isPrime. Иногда разработчики называют такой код самодокументируемым.

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

35

Практические задания

Выполните задания по варианту из табл. 7.

Таблица 7. Варианты заданий

Задания

Задания

Задания

Задания

вар.

вар.

вар.

вар.

 

 

 

 

1

1, 5, 10, 11

6

2, 5, 10, 12

11

3, 5, 10, 11

16

4, 5, 10, 12

2

1, 6, 10, 11

7

2, 6, 10, 12

12

3, 6, 10, 11

17

4, 6, 10, 12

3

1, 7, 10, 11

8

2, 7, 10, 12

13

3, 7, 10, 11

18

4, 7, 10, 12

4

1, 8, 10, 11

9

2, 8, 10, 12

14

3, 8, 10, 11

19

4, 8, 10, 12

5

1, 9, 10, 11

10

2, 9, 10, 12

15

3, 9, 10, 11

20

4, 9, 10, 12

1.Реализуйте функцию min(a, b), возвращающую меньшее из двух чисел.

2.Реализуйте функцию max(a, b), возвращающую большее из двух чисел.

3.Реализуйте функцию sum(a, b), возвращающую сумму двух

чисел.

4.Реализуйте функцию pow(a, n), возводящую a в степень n.

5.Реализуйте функцию min(array), возвращающую наименьшее число из массива.

Примечание. Рекомендуется использовать для этого метод массива forEach.

6.Реализуйте функцию max(array), возвращающую наибольшее число из массива.

Примечание. Рекомендуется использовать для этого метод массива forEach.

7.Реализуйте функцию sum(array), возвращающую сумму всех элементов массива.

Примечание. Рекомендуется использовать для этого метод массива reduce.

8.Реализуйте функцию square(array), возвращающую массив, состоящий из квадратов всех элементов исходного массива.

Примечание. Рекомендуется использовать для этого метод массива map.

9.Реализуйте функцию-генератор sequence(start, step), возвращающую при каждом вызове большее число с указанным шагом.

Примечание. Начальное значение start указывается при вызове генератора, по умолчанию равно 0. Шаг step должен быть необязательным параметром при вызове, по умолчанию равен 1.

10.Реализуйте два метода массива по варианту из табл. 8 вручную, как обычные функции.

36

Таблица 8. Варианты задания

Методы массива

forEach

map

filter

push

(arr, func)

(arr, func)

(arr, func)

(arr, el)

 

pop(arr)

1

6

11

16

shift(arr)

2

7

12

17

unshift(arr, el)

3

8

13

18

reduce(arr, func, init)

4

9

14

19

reverse(arr)

5

10

15

20

Методы массива:

forEach(arr, func) – вызывает func на каждом элементе arr;

map(arr, func) – возвращает массив из результатов func на каждом элементе arr;

filter(arr, func) – возвращает массив только из тех элементов arr, при которых func возвращает true;

push(arr, el) – добавляет el в конец arr;

pop(arr) – удаляет последний элемент arr и возвращает его;

shift(arr) – удаляет первый элемент arr и возвращает его;

unshift(arr, el) – добавляет el в начало arr;

reduce(arr, func, init) (дополнительно) – выполняет func на каждом элементе arr, сохраняя ее результат в аккумуляторе; возвращает новое значение аккумулятора;

reverse(arr) – «на месте» меняет порядок следования элементов на противоположный и возвращает измененный массив.

Во всех функциях выше, кроме reduce, func имеет аргументы func(element, index).

В reduce func(element, index, acc) третий аргумент – начальное значение аккумулятора.

11. Реализовать функцию factorial(n), возвращающую факториал числа n:

с помощью циклов;

с помощью рекурсии.

12. Реализовать функцию fib(n), возвращающую n-е число Фибоначчи:

с помощью циклов;

с помощью рекурсии.

37

2.4. Лабораторная работа и практическое занятие № 4. Области видимости и замыкания

Области видимости функций

Локальные переменные

Переменные, объявленные внутри функции, видны только внутри этой функции.

function showMessage() {

let message = 'Привет, я JavaScript!'; // локальная переменная

console.log ('Привет всем!');

}

showMessage(); // Привет, я JavaScript! console.log (message);

//получится ошибка, так как переменная –

//локальная, то есть видна только внутри функции

Внешние переменные

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

Если одноименная переменная объявляется внутри функции, тогда она перекрывает внешнюю. Например, в коде ниже функция использует локальную переменную userName. Внешняя будет проигнорирована.

let userName = 'Иван'; function showMessage() {

let userName = 'Игорь';

// объявляем локальную переменную

let message = 'Привет, ' + userName; // Игорь console.log (message);

}

//функция создаст и будет использовать свою

//собственную локальную переменную userName showMessage();

console.log (userName); // Иван (не изменилась,

функция не трогала внешнюю переменную)

Глобальные переменные

Переменные, объявленные снаружи всех функций, такие как внешняя переменная userName в вышеприведенном коде, называются глобальными.

Глобальные переменные видимы для любой функции (если только их не перекрывают одноименные локальные переменные).

38

Желательно сводить использование глобальных переменных к минимуму. В современном коде обычно мало или совсем нет глобальных переменных. Хотя они иногда полезны для хранения важнейших «общепроектных» данных.

Замыкания

Замыкание – это функция со всеми внешними переменными, которые ей доступны.

Тем не менее, в JavaScript есть небольшая терминологическая особенность. Обычно, говоря «замыкание функции», подразумевают не саму эту функцию, а именно внешние переменные. Иногда говорят «переменная берется из замыкания». Это означает – из внешнего объекта переменных.

Лексическое окружение

Все переменные внутри функции – это свойства специального внутреннего объекта LexicalEnvironment, который создается при ее запуске. Этот объект называется «лексическое окружение» или просто «объект переменных».

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

В отличие от window, объект LexicalEnvironment является внутренним, он скрыт от прямого доступа. Например:

function sayHi(name) {

var phrase = "Привет, " + name; console.log ( phrase );

}

sayHi('Иван');

При вызове функции:

1. До выполнения первой строчки ее кода, на стадии инициализации, интерпретатор создает пустой объект LexicalEnvironment и заполняет его.

В данном случае туда попадают аргумент name и единственная переменная phrase:

function sayHi(name) {

// LexicalEnvironment = { name: 'Иван', phrase: undefined }

var phrase = "Привет, " + name; console.log ( phrase );

}

sayHi('Вася');

39

2. Функция выполняется.

Во время выполнения происходит присвоение локальной пере-

менной phrase, т.е. свойству LexicalEnvironment.phrase, нового значе-

ния:

function sayHi(name) {

//LexicalEnvironment = { name: 'Иван', phrase: undefined }

var phrase = "Привет, " + name;

//LexicalEnvironment = { name: 'Иван', phrase: 'Привет, Иван'}

console.log ( phrase );

}

sayHi('Иван');

3.В конце выполнения функции объект с переменными обычно выбрасывается и память очищается.

Доступ к внешним переменным

Из функции мы можем обратиться не только к локальной переменной, но и к внешней:

var userName = 'Иван'; function sayHi() {

console.log ( userName ); // 'Иван'

}

Интерпретатор при доступе к переменной сначала пытается найти переменную в текущем LexicalEnvironment, а затем, если ее нет, ищет во внешнем объекте переменных. В данном случае им является window.

Такой порядок поиска возможен благодаря тому, что ссылка на внешний объект переменных хранится в специальном внутреннем свойстве функции, которое называется [[Scope]]. Это свойство закрыто от прямого доступа, но знание о нем очень важно для понимания того, как работает JavaScript.

При создании функция получает скрытое свойство [[Scope]], которое ссылается на лексическое окружение, в котором она была создана.

В примере выше таким окружением является window, так что создается свойство: sayHi.[[Scope]] = window

Это свойство никогда не меняется. Оно всюду следует за функцией, привязывая ее, таким образом, к месту своего рождения. При запуске функции ее объект переменных LexicalEnvironment получает ссылку на «внешнее лексическое окружение» со значением из

[[Scope]].

Если переменная не найдена в функции – она будет искаться снаружи. Именно благодаря этой механике в примере выше

40

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]