03 Js Function Intro

Функции в JavaScript #

Шахматы и зёрна #

Есть такая легенда про зёрна на шахматной доске. О ней можно почитать в Википедии здесь. Суть задачи найти количество зерён и выразить это на компьютерном языке.

Давайте решим задачу математически или вернее рассмотри сразу ответ. Сколько зёрен надо?

Сколько будет 2 в 64 степени? #

  • 2 в 64 степени = 18 446 744 073 709 551 616
  • То есть: 18 квинтиллионов 446 квадриллионов 744 триллиона 073 миллиарда 709 миллионов 551 тысяча 616
  • (2^64 - 1) ответ про зёрна на шахматной доске

Типичное решение задачи в JavaScript #

let result = Math.pow(2, 64) - 1;
// или
let myLovelyResult = 2 ** 64 - 1;

Оба результата в JS вернут “18446744073709552000”. Это несколько отличается от результата выше. Давайте сравним:

  • 18_446_744_073_709_552_000 -> Js
  • 18_446_744_073_709_551_616 -> Математика

Разница в ответе обязует меня рассказать про то:

  1. как так получилось,
  2. что с этим можно сделать начинающему программисту
  3. какой ответ правильный
  4. и вообще как дальше жить, если даже компьютеры обманывают.

Как так получилось #

Вообще в JavaScript значения с типом данных Number являются 64 битными переменными. НО. Всегда есть НО. Переменные Number могут быть не только целыми, но и дробными, а также не только положительными, но и отрицательными. Не ставлю перед собой задачу запутать вас больше, чем этого требует ситуация. Итог - в Number мы можем хранить 2^53 - 1. И максимальное возможное число:

  • Number.MAX_SAFE_INTEGER - 9_007_199_254_740_991

Что с этим можно сделать начинающему программисту #

Мы должны осознать, что внезапно можем упереться либо в свои возможности, либо в возможности языка. Если хотите, то в строительстве тоже есть границы. Мы не можем просто так построить дом из трёхсот этажей. И 300 этажей из архитектуры это наши границы для типов данных. И это входит в основы, в базовые знания при изучении языков. JavaScript выделяет для наших данных определённое место в памяти. И мы ограничены возможностями языка. Забегая вперёд, конечно же можно решить любую задачу, в том числе и эту. Но это не совсем повседневная проблема и инструменты для её решения мы изучим немного позже. После того, как научимся использовать базовые.

Какой ответ правильный #

Представим себе ситуацию, что к нам пришёл клиент, который решил узнать сколько этих зёрен в итоге. Сам он не знает ни программирование, ни тем более математику. Наша задача, как программистов не решить задачу, а скорее удовлетворить клиента. Вернее не так. Результатом нашей работы может быть и простая консультация, которая объясняет клиенту, что данное количество зёрен просто гигантское число и столько зёрен до сих пор не выросло на нашей планете.

Правильным ответом в итоге считается: #

  1. Математическое решение
  2. Консультация, что в лоб эту задачу решить нельзя и на сколько важна программа, если прописать ответ цифрами на бумаге.
  3. Очевидно, что идеальное решение, это то которое укажет почему эту задачу нельзя решить в JS с указанием 2^53 - 1. Возможно заказчик подыскивает подходящий инструмент и это не JS. Мы этого пока не знаем.
  4. Правильным решением может являться и let myLovelyResult = 2**64 - 1;. Если мы протестируем это ручками и поймём, что на каком-то этапе вычисления ломаются.

И здесь мы подошли к необычайно важному пониманию. Наш код нуждается в тестировании. Даже в заведомо простой задаче в два действия мы смогли сделать ошибку.

Тестирование кода #

Именно такие ошибки в одно действие с примерно такой же проблематикой приводят к человеческим потерям.

Когда для вывода на экране самолёта графика линии полёта для скалирования этой линии при выводе на маленький экран программист делит свои данные на высоту самолёта над землёй. Над землёй это над уровнем моря. Ведь земля как бы везде разная. И ориентируясь общепринятым уровнем нам легче работать. Проблема в том, что существует несколько точек на планете с отрицательным “уровнем моря”. В Китае, Израиле, Египте и так далее. В таких впадинах при пересечении точки ноль наша программа делит на ноль…

А мы все знаем, что в жизни категорически запрещено делать всего две вещи: смотреть на сварку и делить на ноль. Тестирование важно. На хабре есть статья с Катастрофические последствия программных ошибок, где приведены некоторые примеры, ошибки в которых обошлись слишком дорого. Цена - жизни.

Мы вряд ли будем работать в авиации, в медицине, в автомобилестроении или любой другой отрасли, где от наших ошибок могут пострадать жизни людей. Но сегодня, восьмого июня 2021-го года, во время написания статьи прошла новость, что __ Reddit, GitHub, Twitch и сайты крупнейших СМИ перестали открываться из-за сбоя у крупного провайдера Fastly.__

Цена ошибки у провайдера миллионы долларов потерь у клиентов. Уверен, что делая всего лишь только сайты мы хотим что бы наши клиенты были довольны. А не того, что бы они приезжали к нам ночью с братками разбираться по поводу куда делись их данные и почему у нас не было бэкапов.

Тестирование и Number #

Ситуация с Number, на самом деле намного хуже. В будущем вы будете вынуждены работать с библиотеками, которые сделали другие программисты. Часть библиотек, которые нам нужны при работе с браузерами WebAPI возвращают нам значения в рамках 32bit. И мы должны аккуратно относится к результатам работы чужого кода.

Как выглядит тестирование #

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

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

let a = 10;
let b = 20;
let square = a * b; 

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

Если мы многократно будем переписывать значения А и Б в коде, то у нас будет слабо понятная простыня кода уже на десятой-двадцатой проверке. Что бы избежать этого мы можем написать код. Так что бы мы его могли переиспользовать. Для этого у нас есть конструкция функций.

Мы уже видели фукнции, это например alert(“Hello”); или Math.pow(2, 64). Точно так же мы можем создать и свою функцию. В которой мы сохраним свои математические или физические формулы. Объявляется функция с помощью ключевого слова function и имени которое мы сами придумываем для функции. Имя должно быть подобрано так, что бы спустя и 2 года, мы сами смогли догадаться что именно она делает. Например, функцию которая находит площадь прямоугольника можно так и назвать findArea или findSquare. В итоге код помещённый в конструкцию функции будет выглядеть вот так:

function findSquare() {
    let a = 10;
    let b = 20;
    let square = a * b;
}

С помощью директивы findSquare(); мы можем запустить работу нашей программы.

findSquare();

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

function findSquare() {
    let a = 10;
    let b = 20;
    let square = a * b;
    console.log(square);
}

findSquare();

Это уже лучше. Но всё ещё не совсем то, что используют в жизни настоящие программисты. В идеале наша функция должна быть в состоянии принимать новые значения. Для этого мы можем указать параметры, которые нужны для работы нашей функции. Это простые переменные А и Б. Без них мы не можем высчитать площадь. И мы можем их сразу затребовать при запуске. Для этого в круглые скобки мы добавим наши аргументы.

function findSquare(a, b) {
    let square = a * b;
    console.log(square);
}

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

findSquare(10, 20);

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

Обычно компьютеру просто надо значение, и функция в подавляющем большинстве случаев должна вернуть это значение. Возвращает значение ключевое слово return. При вызове оператора return в функции её выполнение прекращается. То есть это долажна быть последняя директива в функции. Добавим её.

function findSquare(a, b) {
    let square = a * b;
    return square;
}

Давайте я прочитаю вам, то что я написал.

Мы создали функцию для нахождения площади прямоугольника и назвали её findSquare. Эта функция должна принимать стороны прямоугольника. Мы принимаем их как параметры функции A и B. Внутри функции мы создаём переменную площади прямоугольника, которую называем по-английски square. Мы декларируем её с помощью ключевого слова let. И инициализируем или присваиваем ей значение произведением наших аргументов. Найдя это произведение мы сразу же отдаём или правильнее возвращаем это значение. Возвращаем тому, кто запустил эту функцию.

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

let myOutput = findSquare(10, 20);

Как вариант, представьте себе ситуацию, что вы приходите в спортивный магазин купить палки для скандинавской ходьбы. Наверняка знаете Nordic Walking. Вы выбираете палки для подарка, берёте какие-то суперфирменные палки за 100€, например Leki Smart Flash Nordic Walking и идёте к кассе. На кассе продавщица засканировала этикетку и на маленьком мониторе высветилась цена за ваши палки.

Так вот. Засканировала этикетку - это запустила метод findPrice(qrCode), который принимает наш qrCode, а выдаёт цену в евро. И выдаёт это возвращает наше значение, которое принимает наш терминал и выводит на графический экран. Самый примитивный экран, который только можно представить экран допотопного кассового аппарата.

Если хотите, то наша консоль это модель этого экрана. Мы делаем простые вещи, результат которых мы можем ПОКА вывести на экран в консоли. А вот когда подрастём, то сможем выводить и на других экранах.

И так. Давайте попробуем на примере решить следующие задачи:

  1. Найти площадь и периметр квадрата
  2. Найти площадь и периметр прямоугольника
  3. Найти площадь и периметр куба
  4. Написать программу для вычисления площади круга.
  5. Найти длину окружности.
  6. Написать формулу вычисления стоимости Евро, если курс Евро к Доллару 1,1.
  7. Найти соотношение площади Беларуси к площади Украины.
  8. Найти, во сколько раз площадь Москвы больше площади Берлина.
  9. Если клиент положил в банк 1000€ под 3,5%, какая сумма будет его ждать через семь лет?
comments powered by Disqus