Skip to content

Latest commit

 

History

History
802 lines (499 loc) · 75.2 KB

File metadata and controls

802 lines (499 loc) · 75.2 KB

Вы не знаете JS: Начните и Совершенствуйтесь

Глава 1: Введение в программирование

Добро пожаловать в серию книг Вы не знаете JS (You don't know JS - YDKJS).

Книга Приступим! — введение в некоторые базовые концепции программирования, конечно, с намеренным уклоном в JavaScript (часто сокращаемый до JS) и еще она о том как подступиться и понять оставшиеся книги серии. Эта книга кратко проанализирует что именно вам нужно, чтобы приступить, особенно если вы только начинаете программировать, в том числе на JavaScript.

Эта книга начинается с объяснения базовых принципов программирования на самом высоком уровне. Она в основном предназначена для тех из вас, кто начинает YDKJS имея малый или не имея вовсе опыта в программировании и кто рассчитывает, что эти книги помогут встать на путь понимания программирования сквозь призму JavaScript.

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

Если вы хорошо знаете общие основы программирования, глава 2 подтолкнет вас к более близкому знакомству с духом программирования на JavaScript. Глава 2 знакомит с тем, что такое JavaScript, но, обращаю ваше внимание еще раз, это не подробное руководство — это то, за что выступают остальные книги YDKJS!

Если вы уже довольно комфортно чувствуете себя в JavaScript, сначала ознакомьтесь с главой 3 для беглого знакомства с тем, чего ожидать от YDKJS, а затем приступим!

Код

Начнем с начала.

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

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

Операторы

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

a = b * 2;

Символы a и b называются переменными (см. «Переменные»), которые примерно как обычные коробки, в которых вы можете хранить что угодно. В программах переменные хранят значения (например, число 42), используемые программой. Представляйте их как символьную подмену для самих значений.

В противоположность им, 2 — это само значение, называемое литеральным значением, поскольку оно само по себе и не хранится в переменной.

Символы = и * — это операции (см. «Операции»), они выполняют действия со значениями и переменными, такие как присваивание и математическое умножение.

Большинство операторов в JavaScript заканчиваются точкой с запятой (;).

Оператор a = b * 2; сообщает компьютеру, грубо говоря, взять текущее значение из переменной b, умножить это значение на 2, а затем сохранить результат в другую переменную, которую мы назвали a.

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

Выражения

Операторы состоят из одного или более выражений. Выражение — это любая ссылка на переменную или значение или набор переменных и значений, объединенных операциями.

Например:

a = b * 2;

У этого оператора 4 выражения:

  • 2 — это выражение литерального значения
  • b — это выражение переменной, которое тут означает извлечение его текущего значения
  • b * 2 — это арифметическое выражение, в данном случае выполнение умножения
  • a = b * 2 — это выражение присваивания, в данном случае это присвоить результат выражения b * 2 переменной a (подробнее о выражениях далее)

Типичное выражение, которое является законченным, называется оператор-выражение, например, такое как это:

b * 2;

Этот пример оператора-выражения не является типовым или полезным, и в целом не оказывает никакого эффекта на выполнение программы — он всего лишь извлекает значение b и умножает его на 2, но затем ничего не делает с результатом.

Более распространенный оператор-выражение — это оператор-выражение вызова (см. «Функции»), поскольку весь оператор — это выражение вызова функции:

alert( a );

Выполнение программы

Так как же эти наборы программных операторов сообщают компьютеру что нужно делать? Программу нужно выполнить, также говорят запуск программы.

Операторы, подобные a = b * 2, понятны для разработчиков как при чтении, так и записи, но фактически в такой форме они не понятны напрямую компьютеру. Поэтому используется специальная утилита в компьютере (либо интерпретатор, либо компилятор) для перевода кода, который вы пишете, в команды, понятные компьютеру.

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

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

Обычно утверждают, что JavaScript — интерпретируемый, так как ваш исходный код на JavaScript обрабатывается каждый раз, когда запускается. Но это не совсем точно. Движок JavaScript на самом деле компилирует программу на лету и затем сразу же запускает скомпилированный код.

Примечание: Подробнее о компиляции JavaScript смотрите в первых двух главах книги Область видимости и замыкания этой серии.

Попробуйте сами

Эта глава проиллюстрирует каждое понятие из программирования простыми примерами кода, полностью написанными на JavaScript (очевидно!).

Нельзя не отметить, что пока вы продвигаетесь по этой главе вам может понадобиться перечитать её несколько раз и вам следует практиковаться в каждом из понятий набирая код самостоятельно. Простейший путь сделать это — это открыть консоль в средствах разработки в ближайшем браузере (Firefox, Chrome, IE и т.п.).

Подсказка: Обычно вы можете запустить консоль разработчика с помощью горячих клавиш или из меню. Подробнее о запуске и использовании консоли в вашем любимом браузере см. “Mastering The Developer Tools Console” (http://blog.teamtreehouse.com/mastering-developer-tools-console). Чтобы ввести несколько строк в консоли за раз, используйте <shift> + <enter>, чтобы переместиться на новую строку. Как только вы просто нажмете <enter>, консоль выполнит всё, что вы написали.

Давайте познакомимся с процессом запуска кода в консоли. Сперва я предлагаю открыть пустую вкладку в браузере. Я предпочитаю делать это набирая about:blank в адресной строке. Затем убедитесь, что ваша консоль разработчика, о которой мы только что упоминали, открылась.

Теперь наберите этот код и посмотрите как он выполняется:

a = 21;

b = a * 2;

console.log( b );

Набрав в консоли вышеуказанный код в браузере Chrome мы увидим что-то вроде этого:

Вперед, попробуйте! Наилучший путь обучения программированию — это начать писать код!

Вывод

В предыдущем кусочке кода мы использовалиconsole.log(..). Давайте взглянем вкратце о чем же эта строка кода.

Возможно вы это предполагали, но это и в самом деле то, как мы печатаем текст (т.е. вывод для пользователя) в консоли разработчика. Есть две характеристики этого оператора, которые нам следует пояснить.

Первая часть, log( b ) указывает на вызов функции (см. «Функции»). Здесь получается, что мы передаем переменную b в эту функцию, которая берет значение b и печатает его в консоли.

Вторая часть, console. — это ссылка на объект, где расположена функция log(..). Мы рассмотрим объекты и их свойства более детально в главе 2.

Еще один путь вывести информацию — запустить оператор alert(..). Например:

alert( b );

Если вы запустите этот оператор, то заметите, что вместо вывода значения в консоль он показывает всплывающее окно с кнопкой «OK» и содержимым переменной b. Однако использование console.log(..) обычно лучше помогает кодировать и запускать программы в консоли, чем использование alert(..), потому что вы можете вывести несколько значений за раз без остановки в интерфейсе браузера.

В этой книге мы будем использовать для вывода console.log(..).

Ввод

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

Самый распространенный путь — показать элементы формы на HTML-странице (например, строки ввода) для пользователя, чтобы он мог вводить туда данные, а затем, используя JS, считать эти значения в переменные программы.

Но есть более простой путь получать входные данные в целях обучения и демонстрации, который вы будете использовать на протяжении всей этой книги. Используйте функцию prompt(..):

age = prompt( "Please tell me your age:" );

console.log( age );

Как вы уже могли догадаться, сообщение, которое вы передаете в prompt(..), в данном случае "Please tell me your age:" ('"Пожалуйста сообщите мне свой возраст:"'), выводится во всплывающем окне.

Это может выглядеть примерно так:

Как только вы подтвердите ввод текста щелкнув по «OK», вы заметите, что введенное значение теперь хранится в переменной age, которую мы затем выведем с помощью console.log(..):

Для упрощения, пока мы изучаем основные понятия программирования, примеры в этой книге не потребуют ввода. Зато теперь вы увидели как пользоваться prompt(..). Если вы хотите проверить себя, то можете попробовать использовать ввод в порядке экспериментов с примерами.

Операции

Операции — это те действия, которые мы выполняем над переменными и значениями. Мы уже видели две операции JavaScript, = и *.

Операция * выполняет математическое умножение. Достаточно просто, не так ли?

Операция = используется для присваивания — сначала мы вычисляем значение с правой стороны (исходное значение) от =, а затем записываем его в переменную, которую мы указываем с левой стороны (переменная назначения).

Предупреждение: Такой обратный порядок для присваивания может выглядеть немного странно. Вместо a = 42 кто-то может предпочесть поменять порядок, чтобы исходное значение было слева, а переменная назначения — справа, например 42 -> a (это — неправильный JavaScript!). К сожалению, форма a = 42 и похожие на нее практически полностью превалируют в современных языках программирования. Если вам такой порядок присваивания кажется неестественным, потратьте некоторое время на привыкание к нему.

Пример:

a = 2;
b = a + 1;

Тут мы присваиваем значение 2 переменной a. Затем мы получаем значение переменной a (пока еще 2), прибавляем к нему 1 получая в результате 3, потом сохраняем это значение в переменной b.

Хоть и не являющееся технически операцией, вам необходимо ключевое слово var в любой программе, поскольку это основной способ, с помощью которого вы объявляете (т.е. создаете) переменные (сокращение от variables) (см. «Переменные»).

Вы всегда должны объявить переменную с именем до того, как начнете её использовать. Но вам достаточно объявить переменную всего раз для каждой области видимости (см. «Область видимости»), а затем пользоваться ею столько раз, сколько нужно. Например:

var a = 20;

a = a + 1;
a = a * 2;

console.log( a );	// 42

Вот несколько самых базовых операций в JavaScript:

  • Присваивание: = как в a = 2.

  • Математические: + (сложение), - (вычитание), * (умножение) и / (деление), как в a * 3.

  • Составное присваивание: +=, -=, *= и /= — это составные операции, которые объединяют математическую операцию с присваиванием, как в a += 2 (эквивалентно a = a + 2).

  • Инкремент/Декремент: ++ (инкремент), -- (декремент), как в a++ (эквивалентно a = a + 1).

  • Доступ к свойству объекта: . как в console.log().

    Объекты — это значения, которые хранят другие значения под своими именами, называемые свойства. obj.a означает значение из объекта obj из его свойства a. Еще один способ доступа к свойствам — obj["a"]. См. главу 2.

  • Равенство: == (нестрогое), === (строгое), != (нестрогое неравенство), !== (строгое неравенство), как в a == b.

    См. «Значения и типы» и главу 2.

  • Сравнение: < (меньше чем), > (больше чем), <= (меньше или нестрого равно), >= (больше или нестрого равно), как в a <= b.

    См. «Значения и типы» и главу 2.

  • Логические: && (и), || (или), как в a || b, которое выбирает или a, или (or) b.

    Эти операции используются для создания составных условных конструкций (см. «Условные конструкции»), например: если либо a либо (or) b — истина.

Примечание: Для более детального рассмотрения и охвата операций, не рассмотренных здесь, см. the Mozilla Developer Network (MDN)'s “Expressions and Operators“ (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators).

Значения и типы

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

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

Если затем вы спросите включено ли в комплект поставки телефона зарядное устройство, то ответ может быть только «да» или «нет».

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

Эти разнообразные представления для значений называются типы в терминологии программирования. В JavaScript есть встроенные типы для каждого из этих так называемых примитивных значений:

  • когда вам нужно работать с математикой, вам нужно число.
  • когда вам нужно вывести значение на экран, вам нужна строка (один или несколько символов, слов, предложений).
  • когда вам нужно принять решение в своей программе, вам нужно логическое значение (true (истина) или false (ложь)).

Значения, непосредственно включаемые в исходный код, называются литералы. строковые литералы заключаются в двойные кавычки "..." или одинарные ('...') — единственная разница в них — это ваши стилистические предпочтения. Литералы числа и логического значения пишутся как есть (т.е., 42, true и т.д.).

Пример:

"Я - строка";
'Я - тоже строка';

42;

true;
false;

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

Преобразование между типами

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

JavaScript предоставляет несколько различных возможностей принудительного приведения между типами. Например:

var a = "42";
var b = Number( a );

console.log( a );	// "42"
console.log( b );	// 42

Использование Number(..) (встроенная функция), как было показано выше, это явное приведение из любого другого типа в тип число. Это выглядит достаточно очевидно.

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

При сравнении строки "99.99" с числом 99.99 многие согласятся, что они равны. Но они ведь не совсем одно и то же, не так ли? Это одно и то же значение в двух разных представлениях, двух разных типов. Вы могли бы сказать, что они «нестрого равны», разве нет?

Чтобы помочь вам в таких стандартных ситуациях, JavaScript иногда вмешивается и неявно приводит значения к подходящим типам.

Поэтому если вы используете операцию нестрогого равенства == для сравнения "99.99" == 99.99, JavaScript преобразует с левой стороны "99.99" в его числовой эквивалент 99.99. После этого сравнение превращается в 99.99 == 99.99, которое конечно является истинным.

Несмотря на то, что неявное приведение было задумано, чтобы помочь вам, оно может привести в замешательство, если вы не уделили достаточно времени изучению правил, которые определяют его поведение. У большинства JS-разработчиков никогда его нет, поэтому общее отношение выражается в том, что неявное приведение сбивает с толку и вредит программам внося непредвиденные ошибки и поэтому следует его избегать. Иногда его даже называют изъяном дизайна языка.

Однако, неявное приведение — это механизм, который может быть изучен и даже более того должен быть изучен любым, кто хочет серьезно заниматься программированием на JavaScript. Не только потому, что после изучения его правил оно не будет смущать вас, оно может в самом деле улучшить ваши программы! Усилия того стоят!

Примечание: Для получения более подробной информации о приведении см. главу 2 этой книги и главу 4 книги Типы и синтаксис этой серии.

Комментарии в коде

Сотрудник салона сотовой связи может набросать некоторые заметки о возможностях только что выпущенных телефонов или о новых тарифных планах, которые предлагает его компания. Эти заметки только для самого сотрудника — они не предназначены для чтения покупателями. Тем не менее эти заметки помогают сотруднику улучшить свою работу документируя все "как" и "почему" того, что ему следует рассказать покупателям.

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

Ваш компьютер заботится только о машинном коде, последовательности бинарных 0 и 1, которые появляются после компиляции. Есть почти бесконечное количество программ, которые вы могли бы написать и которые состоят из одинаковых последовательностей 0 и 1. Выбор, который вы делаете о том как написать программу, имеет значение не только для вас, но и для других членов вашей команды и даже для самого вашего будущего.

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

Но еще одна важная часть этого процесса — это комментарии в коде. Это кусочки текста в вашей программе, которые вставляются именно для того, чтобы пояснить какие-то вещи для человека. Интерпретатор/компилятор всегда игнорирует эти комментарии.

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

  • Код без комментариев не оптимален.
  • Слишком много комментариев (по одному на каждую строку кода, например) возможно являются признаком плохо написанного кода.
  • Комментарии должны объяснять почему, а не что. Они могут дополнительно объяснять как, когда код особенно сложен.

В JavaScript есть два типа комментариев: однострочный комментарий и многострочный комментарий.

Пример:

// Это - однострочный комментарий

/* А это
       многострочный
             комментарий.
                      */

Однострочный комментарий // подходит если вы собираетесь разместить комментарий прямо над одиночным оператором или даже в конце строки. Всё что написано в строке после // интерпретируется как комментарий (и потому игнорируется компилятором) до самого конца строки. Нет никаких ограничений на то, что должно быть внутри однострочного комментария.

Пример:

var a = 42;		// 42 - смысл жизни

Многострочный комментарий /* .. */ подходит в случае, если у вас есть несколько строк пояснений для вашего кода.

Вот типичный пример использования многострочного комментария:

/* Нижеприведенное значение используется, поскольку
   выяснилось, что оно отвечает
   на любой вопрос во вселенной. */
var a = 42;

Он может появляться в любом месте строки, даже в середине строки, поскольку есть */, обозначающий его окончание. Например:

var a = /* произвольное значение */ 42;

console.log( a );	// 42

Единственное, что не может появляться в многострочном комментарии — это */, так как это будет означать конец комментария.

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

Переменные

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

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

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

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

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

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

var amount = 99.99;

amount = amount * 2;

console.log( amount );		// 199.98

// преобразует `amount` в строку и
// добавляет "$" в начало
amount = "$" + String( amount );

console.log( amount );		// "$199.98"

Переменная amount начинает свой жизненный цикл с хранения числа 99.99, а затем хранит числовой результат amount * 2, который равен 199.98.

Первая команда console.log(..) должна неявно привести это числовое значение к строке, чтобы вывести его в консоль.

Затем оператор amount = "$" + String(amount) явно приводит значение 199.98 к строке и добавляет символ "$" в начало. С этого момента, amount хранит строковое значение "$199.98", поэтому второму оператору console.log(..) не нужно выполнять никакого приведения, чтобы вывести его в консоль.

Разработчики на JavaScript отметят гибкость использования переменной amount для каждого из значений 99.99, 199.98 и "$199.98". Энтузиасты статической типизации предпочтут отдельную переменную, например amountStr, чтобы хранить окончательное представление значения "$199.98", поскольку оно уже будет другого типа.

В любом случае, вы заметите, что amount хранит текущее значение, которое меняется по ходу выполнения программы, иллюстрируя первичную цель переменных: управление состоянием программы.

Другими словами, состояние отслеживает изменения значений при выполнении программы.

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

Вы объявляете эти константы, чаще всего в начале программы, таким образом, чтобы для вас было удобно иметь всего одно место для того, чтобы поменять значение, если нужно. По соглашению, переменные в JavaScript, являющиеся константами, обычно пишутся большими буквами, с подчеркиваниями _ между словами.

Вот глупый пример:

var TAX_RATE = 0.08;	// 8% налог с продаж

var amount = 99.99;

amount = amount * 2;

amount = amount + (amount * TAX_RATE);

console.log( amount );				// 215.9784
console.log( amount.toFixed( 2 ) );	// "215.98"

Примечание: Также как console.log(..) — это функция log(..), доступная как свойство объекта console, toFixed(..) здесь — это функция, которая может быть доступна у числовых значений. Число в JavaScript не форматируется автоматически со знаком валюты — среда выполнения не знает ваших намерений плюс к этому не существует типа для валюты. toFixed(..) позволяет нам указать до скольки знаков после запятой мы хотим округлить число и она возвращает строку при необходимости.

Переменная TAX_RATE — всего лишь константа по соглашению, в этой программе нет ничего, что могло бы предотвратить ее изменение. Но если ставка налога повысится до 9%, мы все еще можем легко обновить нашу программу установив присвоенное TAX_RATE значение в 0.09 всего в одном месте вместо поиска всех вхождений значения 0.08 разбросанных по программе и изменения их всех.

Новейшая версия JavaScript на момент написания этих строк (обычно называемая "ES6") включает в себя новый способ объявления констант, используя const вместо var:

// согласно ES6:
const TAX_RATE = 0.08;

var amount = 99.99;

// ..

Константы полезны также как и переменные с неизменяемыми значениями, за исключением того, что константы также предотвращают случайное изменение где-либо после начальной установки значения. Если вы попытаетесь присвоить любое значение в TAX_RATE после её объявления, ваша программа отвергнет это изменение (а в строгом (strict) режиме, прервется с ошибкой, см. "Строгий режим" в главе 2).

Кстати, такой тип «защиты» против ошибок похож на контроль типов статической типизации, так что вы в какой-то степени поймете почему статические типы в других языках могут быть привлекательными!

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

Блоки

Сотрудник салона сотовой связи должен пройти последовательность шагов для завершения оформления покупки, если вы покупаете новый телефон.

Примерно также в коде нам часто нужно группировать последовательности операторов вместе, которые мы часто называем блоком. В JavaScript блок определяется обрамлением одного или более операторов парой фигурных скобок { .. }. Пример:

var amount = 99.99;

// отдельный блок
{
	amount = amount * 2;
	console.log( amount );	// 199.98
}

Такой вид отдельного блока { .. } вполне допустим, но не часто встречается в JS-программах. Обычно блоки присоединяются к другим управляющим операторам, таким как оператор if (см. «Условные конструкции») или цикл (см. «Циклы»). Например:

var amount = 99.99;

// сумма достаточно велика?
if (amount > 10) {			// <-- блок прикрепляется к `if`
	amount = amount * 2;
	console.log( amount );	// 199.98
}

Мы расскажем об операторе if в следующем разделе, но как вы видите блок { .. } с двумя операторами присоединен к if (amount > 10). Операторы внутри этого блока будут выполнены только при выполнении условия в условной конструкции.

Примечание: В отличие от многих других операторов, таких как console.log(amount);, блоковый оператор не требует точки с запятой (;) в конце оператора.

Условные конструкции

«Хотите ли вы добавить дополнительную защитную пленку в вашу покупку за $9.99?». Предупредительный сотрудник магазина попросил вас принять решение. И вам может сначала понадобиться проинспектировать текущее состояние вашего кошелька или банковского счета, чтобы ответить на этот вопрос. Но, очевидно, что это всего лишь простой вопрос из разряда «да или нет».

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

Самый распространенный из них — это оператор if. По сути, вы говорите, «Если (if) это условие истинно, сделать следующее...». Например:

var bank_balance = 302.13;
var amount = 99.99;

if (amount < bank_balance) {
	console.log( "Я хочу купить этот телефон" );
}

Оператор if требует выражение между скобками ( ), которое может быть интерпретировано либо как истина (true), либо ложь (false). В этой программе мы написали выражение amount < bank_balance, которое конечно же будет вычислено как true или false в зависимости от количества в переменной bank_balance.

Вы даже можете предоставить альтернативу если условие не будет истинным, называющуюся оператором else. Пример:

const ACCESSORY_PRICE = 9.99;

var bank_balance = 302.13;
var amount = 99.99;

amount = amount * 2;

// может ли мы позволить себе дополнительную покупку?
if ( amount < bank_balance ) {
	console.log( "Я возьму этот аксессуар!" );
	amount = amount + ACCESSORY_PRICE;
}
// иначе:
else {
	console.log( "Нет, спасибо." );
}

Тут если amount < bank_balance истинно, мы выведем "Я возьму этот аксессуар!" и добавим 9.99 в нашу переменную amount. В противном случае, оператор else говорит, что мы вежливо ответим "Нет, спасибо." и оставим переменную amount без изменений.

Как мы уже обсуждали ранее в «Значения и типы», значения, которые не совпадают с ожидаемым типом, часто приводятся к этому типу. Оператор if ожидает логическое значение, но если вы передадите что-либо отличное от логического значения, произойдет приведение.

JavaScript определяет список особых значений, которые считаются «ложными», так как при приведении к логическому значению они станут значением false, такие значения включают в себя 0 и "". Любое другое значение, не входящее в список «ложных», автоматически считается «истинным», когда приводится к логическому значению, оно становится равным true. Истинные значения включают в себя такие значения как 99.99 и "free". См. «Истинный и ложный» в главе 2 для получения более детальной информации.

Условные конструкции существуют и в других формах, отличных от if. Например, оператор switch может использоваться как сокращение для последовательности операторов if..else (см. главу 2). Циклы (см. «Циклы») используют условную конструкцию, чтобы определить надо ли завершить выполнение цикла или нет.

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

Циклы

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

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

Цикл включает в себя проверяемое условие и блок (обычно в виде { .. }). Каждый раз, когда выполняется блок в цикле, это называется итерацией.

Например, цикл while и цикл do..while иллюстрируют принцип повторения блока операторов до тех пора пока условие не перестанет быть равным true:

while (numOfCustomers > 0) {
	console.log( "Чем я могу вам помочь?" );

	// помощь покупателю...

	numOfCustomers = numOfCustomers - 1;
}

// против:

do {
	console.log( "Чем я могу вам помочь?" );

	// помощь покупателю...

	numOfCustomers = numOfCustomers - 1;
} while (numOfCustomers > 0);

Единственная разница между этими циклами — это будет ли проверяться условная конструкция до первой итерации (while) или после первой итерации (do..while).

В любом из этих циклов если условная конструкция возвратит false, следующая итерация не будет выполнена. Это значит, что если условие изначально будет false, цикл while никогда не будет выполнен, а цикл do..while выполнится только один раз.

Иногда вы используете цикл для подсчета определенного набора чисел, например от 0 до 9 (десять чисел). Это можно сделать установкой переменной в цикле итерации, например i, в значение 0 и увеличивая его на 1 в каждой итерации.

Предупреждение: По множеству исторических причин языки программирования почти всегда ведут подсчет в нолеподобной манере, т.е. начиная с 0 вместо 1. Если вы не знакомы с таким типом подсчета, поначалу это может сбивать с толку. Уделите некоторое время тому, чтобы попрактиковаться в подсчете, начинающимся с 0, чтобы освоиться в нем!

Условная конструкция проверяется на каждой итерации, как если бы был неявный оператор if внутри цикла.

Для выхода из цикла можно использовать JavaScript-оператор break. К тому же, можно обнаружить, что ужасно легко можно создать цикл, который в противном случае будет работать вечно без механизма break.

Проиллюстрируем:

var i = 0;

// цикл `while..true` будет выполняться вечно, не так ли?
while (true) {
	// прервать цикл?
	if ((i <= 9) === false) {
		break;
	}

	console.log( i );
	i = i + 1;
}
// 0 1 2 3 4 5 6 7 8 9

Предупреждение: Показанное выше не является практикой, которой вы должны придерживаться при реализации ваших циклов. Это представлено только в иллюстративных целях.

Если while (или do..while) может достичь цели вручную, есть еще одна синтаксическая форма, называемая цикл for именно для такой вот цели:

for (var i = 0; i <= 9; i = i + 1) {
	console.log( i );
}
// 0 1 2 3 4 5 6 7 8 9

Как видите, в обоих случаях условная конструкция i <= 9 равна true для первых 10 итераций (i принимает значения от 0 до 9) любой из форм цикла, но становится равным false как только i становится равным 10.

У цикла for есть три составных части: инициализация (var i=0), проверка условия (i <= 9) и обновление значения (i = i + 1). Поэтому если вы собираетесь заниматься выполнением конкретного количества итераций, for будет более компактной и часто более легкой формой цикла для понимания и записи.

Есть другие особые формы циклов, которые предназначены для итерирования по особым значениям, таким как свойства объекта (см. главу 2), где неявная проверка условной конструкции — это все ли свойства или нет уже обработаны. Принцип «цикл работает пока не нарушится условие» соблюдается независимо от формы цикла.

Функции

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

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

Функция — обычно это именованная секция кода, которая может быть «вызвана» по имени и код внутри нее будет при этом запускаться каждый раз. Пример:

function printAmount() {
	console.log( amount.toFixed( 2 ) );
}

var amount = 99.99;

printAmount(); // "99.99"

amount = amount * 2;

printAmount(); // "199.98"

У функций могут быть аргументы (т.е. параметры) — это значения которые вы ей передаете. А также функции могут возвращать значение.

function printAmount(amt) {
	console.log( amt.toFixed( 2 ) );
}

function formatAmount() {
	return "$" + amount.toFixed( 2 );
}

var amount = 99.99;

printAmount( amount * 2 );		// "199.98"

amount = formatAmount();
console.log( amount );			// "$99.99"

Функция printAmount(..) принимает параметр, который мы назвали amt. Функция formatAmount() возвращает значение. Конечно, вы можете комбинировать параметры и возвращаемое значение в одной и той же функции.

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

Пример:

const TAX_RATE = 0.08;

function calculateFinalPurchaseAmount(amt) {
	// вычисляем новую сумму с налогом
	amt = amt + (amt * TAX_RATE);

	// возвращаем новую сумму
	return amt;
}

var amount = 99.99;

amount = calculateFinalPurchaseAmount( amount );

console.log( amount.toFixed( 2 ) );		// "107.99"

Хотя calculateFinalPurchaseAmount(..) вызывается только один раз, выделение её поведения в отдельную именованную функцию делает код, использующий её логику (оператор amount = calculateFinal...), яснее. Если в функции есть несколько операторов, её преимущества будут более очевидны.

Область видимости

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

В программировании есть термин для этого принципа: область видимости (технически называемая лексическая область видимости). В JavaScript каждая функция получает свою собственную область видимости. Область видимости — это в основном коллекция переменных и правила доступа к этим переменным по имени. Только код внутри функции имеет доступ к переменным, действующим в области функции.

Имя переменной должно быть уникальным в рамках одной и той же области видимости — не может быть двух различных переменных a, расположенных рядом друг с другом. Но одно и тоже имя переменной a может появляться в разных областях видимости.

function one() {
	// эта `a` принадлежит только функции `one()`
	var a = 1;
	console.log( a );
}

function two() {
	// эта `a` принадлежит только функции `two()`
	var a = 2;
	console.log( a );
}

one();		// 1
two();		// 2

Также, область видимости может быть вложена внутрь другой области видимости, прямо как клоун на дне рождения надувает один шарик внутри другого. Если одна область вложена в другую, для кода внутри самой внутренней области доступны переменные из окружающей области.

Пример:

function outer() {
	var a = 1;

	function inner() {
		var b = 2;

		// здесь у нас есть доступ и к `a`, и к `b`
		console.log( a + b );	// 3
	}

	inner();

	// здесь у нас есть доступ только к  `a`
	console.log( a );			// 1
}

outer();

Правила лексической области видимости говорят, что код в одной области может иметь доступ к переменным как её самой, так и к переменным любой области снаружи этой области.

Таким образом, код внутри функции inner() имеет доступ к обеим переменным a и b, но у кода в outer() есть доступ только к a — у него нет доступа к b потому что эта переменная внутри inner().

Вспомните этот код, который появлялся выше:

const TAX_RATE = 0.08;

function calculateFinalPurchaseAmount(amt) {
	// вычисляем новую сумму с налогом
	amt = amt + (amt * TAX_RATE);

	// возвращаем новую сумму
	return amt;
}

Константа (переменная) TAX_RATE доступна внутри функции calculateFinalPurchaseAmount(..), даже несмотря на то, что мы не передавали её внутрь, из-за лексической области видимости.

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

Практика

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

Держа это в уме, давайте попробуем попрактиковаться в некоторых принципах, которые мы изучили в этой главе. Я дам вам «требования», а вы попробуете их реализовать. Затем сверьтесь с кодом, приведенным ниже, чтобы увидеть как я их реализовал.

  • Напишите программу для вычисления общей стоимости покупки телефона. Вы будете продолжать покупать телефоны (подсказка: циклы!) пока у вас не закончатся деньги на банковском счете. Вы также будете покупать аксессуары для каждого из телефонов до тех пор, пока сумма покупки не превысит ваш мысленный предел трат.
  • После того, как вы посчитаете сумму покупки, прибавьте налог, затем выведите на экран вычисленную сумму покупки, правильно отформатировав её.
  • Наконец, сверьте сумму с балансом вашего банковского счета, чтобы понять можете вы себе это позволить или нет.
  • Вы должны настроить некоторые константы для «ставки налога», «цены телефона», «цены аксессуара» и «предела трат» также как и переменную для вашего «баланса банковского счета».
  • Вам следует определить функции для вычисления налога и для форматирования цены со знаком валюты и округлением до двух знаков после запятой.
  • Бонусная задача: Попробуйте включить ввод данных в вашу программу, например с помощью prompt(..), рассмотренную ранее в разделе «Ввод». Вы можете, например, запросить у пользователя баланс банковского счета. Развлекайтесь и будьте изобретательны!

Хорошо, вперед. Попробуйте. Не подсматривайте в мой код пока сами не попробуете!

Примечание: Так как это книга о JavaScript, очевидно что я буду решать практические упражнения на JavaScript. Но вы можете сделать это на другом языке, если чувствуете себя в нем более уверенно.

Вот мое решение для этого упражнения, написанное на JavaScript:

const SPENDING_THRESHOLD = 200;
const TAX_RATE = 0.08;
const PHONE_PRICE = 99.99;
const ACCESSORY_PRICE = 9.99;

var bank_balance = 303.91;
var amount = 0;

function calculateTax(amount) {
	return amount * TAX_RATE;
}

function formatAmount(amount) {
	return "$" + amount.toFixed( 2 );
}

// продолжаем покупать телефоны пока у нас остаются деньги
while (amount < bank_balance) {
	// покупаем новый телефон!
	amount = amount + PHONE_PRICE;

	// можем ли мы позволить себе аксессуар?
	if (amount < SPENDING_THRESHOLD) {
		amount = amount + ACCESSORY_PRICE;
	}
}

// не забудьте заплатить налог
amount = amount + calculateTax( amount );

console.log(
	"Ваша покупка: " + formatAmount( amount )
);
// Ваша покупка: $334.76

// можете ли вы в самом деле позволить себе эту покупку?
if (amount > bank_balance) {
	console.log(
		"Вы не можете позволить себе эту покупку. :("
	);
}
// Вы не можете позволить себе эту покупку. :(

Примечание: Простейший способ запустить эту JavaScript программу — набрать её в консоли разработчика в вашем браузере.

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

Резюме

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

Они действуют подобно строительным блокам. Чтобы построить высокую башню, вы начинаете класть блок на блок, блок на блок. То же самое и в программировании. Вот несколько необходимых строительных блоков в программировании:

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

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

Наконец, не пренебрегайте мощью практики. Лучший путь научиться как писать код — это писать код.

Я рад, что вы теперь на верном пути к изучению написания кода! Так держать! Не забудьте ознакомиться с другими ресурсами по программированию для начинающих (книги, блоги, онлайн-тренировки и т.д.). Эта глава и эта книга — это большой старт, но они — всего лишь краткое введение.

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