Файл: Основные правила работы с функциями: примеры и ограничения использования функций в различных языках программирования.pdf

ВУЗ: Не указан

Категория: Курсовая работа

Дисциплина: Не указана

Добавлен: 31.03.2023

Просмотров: 55

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

Введение

Функции являются одними из главных концептов в программировании. Они позволяют разделять программы на так называемые подпрограммы, что, в свою очередь, позволяет коду быть модулярнее и проще. Функции также решают проблему повторения кода (англ. code repetition).

Концепт функций в программировании не нов. Ещё в языке Ассемблера присутствовали так называемые процедуры, которые очень похожи на функции в современных языках программирования. Существуют целые функциональные языки программирования, где функция – основной структурный элемент программы. Таким образом, функции – одни из важнейших элементов программирования. Они используются повсюду. Вы не найдёте не одной серьёзной программы, в которой нет функций.

В этой работе мы рассмотрим основные правила, теорию и практическое использование функций в языках JavaScript и С#.

В работе использованы три источника: книга ‘Eloquent JavaScript’, Сайт ‘Mozilla Developers Network (MDN)’ и официальная документация языка C# от Microsoft. Кратко о достоверности этих источников:

  • Книга ‘Eloquent JavaScript’ признана одной из лучших книг по основам программирования и, в частности, JavaScript. Она довольно популярна у начинающих.
  • MDN – официальная документация веб-технологий от Mozilla, компании создавшей Firefox, популярный броузер. MDN очень популярен среди программистов JavaScript.
  • Официальная документация C# от Microsoft, создателя языка – самый надёжный источник знаний о C#.

Глава 1

Теория и базовое использование

1.1 Теория

Главная цель функций – разделение программ на подпрограммы. Так что такое подпрограммы? Подпрограммы – это части кода, отделённые от основной программы, которые получают входные данные и выдают (возвращают) выходные данные. Входные данные называют аргументами или параметрами, а выходные данные - возвращаемым значением (англ. return value). В отличии от математических функций, функции в программирование могут не принимать аргументы и не возвращать данные [1].

Каждая функция имеет имя, с помощью которого она может быть использована и так-называемое тело, в котором и написан сам код функции [2]. Тело функции может содержать любой код, который мог быть написан вне функции. Этот код может, в том числе, использовать другие функции и даже вызывать сам себя. Когда функция использует сама себя, это называется рекурсия (англ. recursion) [3], мы рассмотрим её позже.


Переменные, объявленные внутри кода функции, работают только внутри этой функции, однако функции могут менять значения глобальных переменных. Этот концепт называется область видимость переменный (англ. variable scope) [4].

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

1.2 Синтаксис

Теперь, давайте поподробнее разберём синтаксис функций. Начнём с JavaScript. Рассмотрим пример одной функции.

function add(a, b) {

return a + b;

}

  • ‘function’ – ключевое слово обозначающее создание функции.
  • ‘add’ – название функции.
  • ‘()’ – обозначает место для аргументов. Эти скобки должны присутствовать даже если функция не имеет аргументов.
  • ‘{}’ – обозначает тело функции.
  • ‘а, b’ – аргументы функции.
  • ‘return’ – обозначает возвращаемое значение.
  • ‘a + b’ – Возвращаемое значение. [5]

Таким образом эта функция принимает 2 аргумента и возвращает сумму этих двух аргументов.

Рассмотрим ещё одну функцию:

function getHalfPI() {

return Math.PI / 2;

}

Эта функция не принимает аргументов, но возвращает значение, в данном случае число ПИ делённое на 2 [6].

Рассмотрим третьею функцию:

function logSomething() {

console.log("Привет Мир, я из функции");

}

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

Теперь, давайте рассмотрим пример использования вышеописанных функций. Начнём с функции ‘add’.

var sum = add(10, 9);

Таким образом мы присваиваем переменной sum значение, возвращённое функцией add, в данном случае – 19.

Перейдём к функции ‘getHalfPI’.

var halfPi = getHalfPI();

console.log(halfPi); // 1.5707963267948966

Здесь единственное отличие от первого примера – отсутствие аргументов у функции ‘getHalfPI’.

Рассмотрим пример функции ‘logSomething’

logSomething(); // Привет Мир, я из функции

В данном случае мы не присеваем значение переменной, так как функция ничего не возвращает, а просто выполняет функцию ‘console.log’, результат которой мы видим в консоли.

Перейдём на C#.

Рассмотрим аналог функции ‘add’.

int add(int a, int b) {

    return a + b;

}

  • ‘int’ – тип значения, возвращаемого функцией. Если функция ничего не возвращает тип должен быть ‘void’.
  • ‘add’ – название функции.
  • ‘()’ – обозначает место для аргументов. Эти скобки должны присутствовать даже если функция не имеет аргументов.
  • ‘{}’ – обозначает тело функции.
  • ‘int а, int b’ – аргументы функции с их типами.
  • ‘return’ – обозначает возвращаемое значение.
  • ‘a + b’ – Возвращаемое значение. [7]

Как видите, разница в синтаксисе объявления функций в JS и C# минимальна, так как оба языка C-подобные. Основная разница в том что в C# статическая типизация, а в JS динамическая, что означает что в C# мы должны указывать тип возвращаемого значения и аргументов, а в JS нет.

Также давайте рассмотрим аналоги функций ‘getHalfPI’ и ‘logSomething’.

double getHalfPI() {

    return Math.PI;

}

void logSomething() {

    Console.WriteLine("Привет Мир, я из функции");

}

Рассмотрим также примеры использования функций в C#.

int sum = add(10, 9);

double halfPi = getHalfPI();

Console.WriteLine(halfPi);

logSomething(); // Привет Мир, я из функции

1.3 Практический пример

Давайте рассмотрим пример одного алгоритма, где функции могут упростить код.

JavaScript:

var data = [1, 3, 6, 5, 4, 1, 2, 3, 5, 9];

// Задача: вычислить среднее значение массива 'data'

var total = 0;

for(var i = 0; i < data.length; i++) {

total = total + data[i];

}

// Результат:

var result = total / data.length;

А теперь то же самое, но с использованием функции:

var data = [1, 3, 6, 5, 4, 1, 2, 3, 5, 9];

// Функция для расчёта среднего значение массива

function arrayAverage(array /* входные данные */) {

// Имплементация алгоритма

var total = 0;

for(var i = 0; i < array.length; i++) {

total = total + array[i];

}

// Возвращение выходных данных

return total / array.length;

}

// Результат:

var result = arrayAverage(data);

В данном случае логика упростилась, однако сама программа стала длиннее. Но что, если на надо рассчитать среднее значение не одного массива, а сразу трёх?

Без функций:

var data1 = [1, 3, 6, 5, 4, 1, 2, 3, 5, 9];

var data2 = [9, 1, 9, 3, 3, 4, 3, 2, 1, 2];

var data3 = [5, 3, 4, 1, 7, 6, 4, 3, 2, 1];

var total1 = 0, total2 = 0, total3 = 0;

for(var i = 0; i < data1.length; i++) {

total1 = total1 + data1[i];

}

for(var j = 0; j < data2.length; j++) {

total2 = total2 + data2[j];

}

for(var k = 0; k < data3.length; k++) {

total3 = total3 + data3[k];

}

// Результат:

var result1 = total1 / data1.length;

var result2 = total2 / data2.length;

var result3 = total3 / data3.length;

С функциями:

var data1 = [1, 3, 6, 5, 4, 1, 2, 3, 5, 9];

var data2 = [9, 1, 9, 3, 3, 4, 3, 2, 1, 2];

var data3 = [5, 3, 4, 1, 7, 6, 4, 3, 2, 1];

function arrayAverage(array) {

var total = 0;

for(var i = 0; i < array.length; i++) {

total = total + array[i];

}

return total / array.length;

}

// Результат:

var result1 = arrayAverage(data1);

var result2 = arrayAverage(data2);

var result3 = arrayAverage(data3);

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

Рассмотрим этот-же пример в C#.

Без функций:

int[] data1 = { 1, 2, 3, 4 };

int[] data2 = { 2, 3, 4, 5 };

int[] data3 = { 3, 4, 5, 6 };

float total1 = 0, total2 = 0, total3 = 0;

for(int i = 0; i < data1.Length; i++) {

    total1 = total1 + data1[i];

}

for(int j = 0; j < data2.Length; j++) {

    total2 = total2 + data2[j];


}

for(int k = 0; k < data3.Length; k++) {

    total3 = total3 + data3[k];

}

float result1 = total1 / data1.Length;

float result2 = total2 / data2.Length;

float result3 = total3 / data3.Length;

C функциями.

int[] data1 = { 1, 2, 3, 4 };

int[] data2 = { 2, 3, 4, 5 };

int[] data3 = { 3, 4, 5, 6 };

float ArrayAverage(int[] array)

{

    float total = 0;

    for(int i = 0; i < array.Length; i++)

    {

        total = total + array[i];

    }

    return total / array.Length;

}

float result1 = ArrayAverage(data1);

float result2 = ArrayAverage(data2);

float result3 = ArrayAverage(data3);

Как видим, плюсы использования функций распространяются на C# так же, как и на JavaScript.

Вывод 1

Функции в программировании позволяют разделять код на подпрограммы и использовать их, используя имя. Функции могут принимать аргументы и возвращать значения. Они позволяют заметно укорачивать программы. Синтаксис функций очень похож в C-подобных языках. Стандартная библиотека – набор готовых функций, которые интегрированы в язык программирования.

Глава 2

Практические техники

2.1 Рекурсия

Рекурсия – это когда функция использует саму себя [8]. Это удобно, когда задачу можно разделить на несколько аналогичных, но более простых задач. Самый знаменитый пример рекурсии – функция факториала. Давайте рассмотрим варианты имплементации этой функции с рекурсией и без неё.

Сначала – имплементация без рекурсии, используя циклы.

function factorial(n) {

    var result = 1;

    for(var i = 1; i <= n; i++) {

        result = result * i;

    }

    return result;

}

А теперь давайте рассмотрим вариант имплементации с использованием рекурсии.

function factorial(n) {

    if(n === 1) return 1;

    return n * factorial(n - 1);

}

На первый взгляд очень трудно понять, что происходит в варианте с рекурсией. Для этого давайте пошагово разберём что делает код в обеих имплементациях, если на пример вызвать функцию с значением 3 (factorial(3)).

Начнём с варианта с циклами:

  1. Сначала значение переменной ‘result’ ровно 1
  2. Первая итерация цикла for. ‘i’ равен 1, ‘result’ равен 1. 1 * 1 = 1
  3. Вторая итерация цикла for. ‘i’ равен 2, ‘result’ равен 1. 1 * 2 = 2
  4. Третья итерация цикла for. ‘i’ равен 3, ‘result’ равен 2. 2 * 3 = 6

Итог: Результат равен 6

А теперь варианта с рекурсией:

  1. Первый вызов функции. n равен 3. Функция возвращает 3 * factorial(2).
  2. Второй вызов функции. n равен 2. Функция возвращает 2 * factorial(1).
  3. Третий вызов функции. n равен 1. Срабатывает if. Функция возвращает 1.
  4. Второй вызов возвращает 2 (2 * 1)
  5. Первый вызов возвращает 6 (3 * 2)

Итог: Результат равен 6

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

Пример без рекурсии:

function pow(number, power) {

    var result = 1;

    for(var i = 0; i < power; i++) {

        result = result * number;

    }

    return result;

}

С рекурсией:

function pow(number, power) {

    if (power === 0) return 1;

    return number * pow(number, power - 1);

}

Пошагово разберём алгоритмы с входными данными number = 5, power = 3.

Сначала алгоритм без использования рекурсии:

  1. Сначала переменная result равна 1.
  2. Первая итерация. result равен 1 * 5 = 5.
  3. Вторая итерация. result равен 5 * 5 = 25.
  4. Третья итерация. result равен 25 * 5 = 125.

Итог: Результат равен 125

Вариант с рекурсией:

  1. Первый вызов функции. power равен 3. Функция возвращает 5 * pow(5, 2).
  2. Второй вызов функции. power равен 2. Функция возвращает 5 * pow(5, 1).
  3. Третий вызов функции. power равен 1. Функция возвращает 5 * pow(5, 0).
  4. Четвёртый вызов функции. power равен 0. Функция возвращает 1.
  5. Третий вызов возвращает 5
  6. Второй вызов возвращает 25
  7. Первый вызов возвращает 125

Итог: Результат равен 125

Рассмотрим ещё одну рекурсивную функцию, на сей раз работающую с массивами.

function searchArray(array, value, index) {

    var index = index || 0;

    

    if(index === array.length) return -1;

    if(array[index] === value) return index;

    return searchArray(array, value, index + 1);

}

Эта функция ищет индекс данного значения в массиве, и возвращает индекс если значение присутствует в массиве, если значение отсутствует функция возвращает значение -1.

Разберём эту функцию поподробнее. Начнём со второй линии кода.

var index = index || 0;

Этот код присваивает переменной ‘index’ значение аргумента ‘index’ или, если аугмент не передан функции, значение 0, то есть индекс первого элемента в массиве.

if(index === array.length) return -1;

Эта строка кода проверяет если индекс равен длине массива, то функция возвращает -1. Это значит, что данное значение не присутствует в массиве.

if(array[index] === value) return index;

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

return searchArray(array, value, index + 1);

Эта строка рекурсивно вызывает нашу функцию с теми же аргументами и индексом больше на 1. Таким образом функция ‘двигается’ по массиву, ища значение.

Теперь рассмотрим аналоги выше приведённых функций в C#.

Первая функция:

int factorial(int n)

{

    if (n == 1) return 1;

    return n * factorial(n - 1);

}

Вторая функция:

int pow(int number, int power)