# Операции, Типы, Сравнение, Условия и Логические операторы. ## Алфавит Код состоит из спецсимволов `~!$%^&*()-_+=\|/?[]:;,.<>"'{}`, букв английского алфавита и цифр ### Словарь 'Словарь' языка делится на две основные части: #### Ключевые слова Эти слова описаны в стандарте языка, и имеют особый смысл. Например слово `var`. С каждым или почти каждым мы ознакомимся в процессе изучения курса. #### Идентификаторы Переменные, имена функций - это идентификаторы. Вы можете их создавать сами. Каждый идентификатор начинается с буквы, `$` или `_`. Со второго символа так же допускается использование цифр: ```javascript var a15 = 15; var camelCaseVariable = "Для отделения слов в идентификаторах можно использовать большие буквы"; var underscore_variable = "или подчерки"; ``` В **JS** принято использовать **camelCase**. #### **JS** - **Case Sensitive**. Это значит, что размер имеет значение. Букв. Т. е. переменные `AaA` и `aAa` это *разные* переменные. Ключевые слова в **JS** пишутся маленькими буквами, и подсветка это показывает: ```javascript var a = 5; VAR b = 10; ``` ## Присвоение Одна из основных операций, без которой не обходится практически ни одна строка кода - операция **присвоения**, т. е. связывания имени переменной с определенным значением: ```javascript var1 = value1; ``` **Слева** от знака равенства **должна** быть переменная, **справа** - **выражение**. **Присвоение** происходит по следующему алгоритму: - Выражение справа *вычисляется* - *Значение* выражения запоминается где-то в недрах **JS** - переменная слева связывается со значением. Таким образом, в программировании имеют смысл бессмысленные с математической точки зрения вещи: ```javascript var a = 5; a = a +1; ``` **Во всех** случаях, кроме присвоения, когда переменная встречается в коде, её значение подставляется в это место как подвыражение, т. е. происходит чтения значения переменной. ## `;` Во многих языках программирования, каждый **оператор** отделяется от других с помощью символа `;`. Это подсказка интерпретатору или компилятору языка. В **JS** практически всегда можно обойтись без этих символов, однако в некоторых случаях они обязательны, например, если несколько операторов находятся в одной строке: ```javascript a = 5; b = a + 5; ``` Однако *обычно* нет причин для написания операторов в одну строку. ## Типы данных и операции над ними **Тип данных** - это множество допустимых значений, как было уже упомянуто. ### Операции над данными. Операции зависят от типа данных, и зачастую имеют смысл для одного типа данных и не имеют его для других. Например нет смысла делить на `Boolean` или дату, однако *иногда* есть смысл делить на строку (если в ней число). С этим бывают определенные сложности. ![Девочка в шоке](http://img1.joyreactor.cc/pics/post/%D0%BA%D0%B0%D1%80%D1%82%D0%B8%D0%BD%D0%BA%D0%B8-javascript-%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5-3340155.jpeg "Девочка в шоке") ### Числа. Вы уже знакомы с числами: ```javascript var b = 5 var c = 6.57 var myPi = Math.PI ``` В JS для целых и дробных существует единый тип `Number`. Так же этот тип имеет специальные значения `NaN` (Not A Number), `+Infinity` и `-Infinity` (бесконечность). ```javascript 4/"asdf" // бессмысленное выражение, как результат - NaN ``` ```javascript 15/0 // на ноль делить нельзя, но в высшей математике - можно :-) ``` #### Основные операции над числами: - Сложение - Вычитание - Умножение - Деление - Остаток от деления `%` ##### Сокращенные формы: операции и присвоение: ```javascript var b = 5; b += 2; var a = 5; a %= 2; ``` > Поэксперементируйте и объясните, что происходит в примере выше, а так же как выглядит *не* сокращенная форма операций выше. #### Инкремент и декремент - Преинкремент (увеличение на 1) `++a` - Предекремент (уменьшение на 1) `--a` - Постинкремент (увеличение на 1) `a++` - Постдекремент (уменьшение на 1) `a--` > Поэксперементируйте и объясните, в чем разница между пост- и пре- инкрементом и декрементом. #### `Math` Множество нужных операций по работе с числами есть в объекте-коллекции `Math`, который является частью стандартной библиотеки: ```javascript alert(Math.random()); var a = 5; var aBy2 = Math.floor(a/2); var aModulo = a % 2; ``` Больше информации о `Math`: https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/Math ### Строки Строка - тип `String`. Некое множество символов. Для перевода строки в число используйте `+` или `parseInt` ( для целых ) или `parseFloat` ( для чисел с дробной частью ) ```javascript var someString = "foo"; var concatenatedString = someString + " bar"; var stringWithNumberInside = "123"; var integerNumberByString = +stringWithNumberInside; var floatNumberByString = parseFloat("-15.15"); ``` ### Boolean `true` (правда) или `false` (ложь) В основном используется для двух задач: - Та или иная переменная-флаг для внутреннего использования. Например `isLoggedIn` может показывать залогинен пользователь на сайте или нет: ```javascript var isLoggedIn = true var isLoggedIn = false ``` - Как результат той или иной логической операции: ```javascript var isLoggedIn = (password == rightPassword) && (login == rightLogin) //пользователь залогинен, если пароль и логин совпадают с верными var isUserOldEnoughToSeeTheAdultVideos = age > 18 // пользователь может смотреть видео, если ему больше 18 лет. ``` Логическое выражение может использоваться в условиях, которые делают или не делают определенные операции в зависимости от истинности условия. ### Array Сложная структура данных, обращение к элементам которого происходит по целочисленному индексу, начинающемуся с нуля: ```javascript var a = [0,1,2,3,4]; var squaresOfA = a.map(function(item){ return item*item; }); ``` Обращение к элементами приосходит с помощью `[]`: ```javascript alert(a[4]); alert(squaresOfA[4]); var cubesOfA = []; cubesOfA[0] = a[0]*a[0]*a[0]; cubesOfA[1] = a[1]*a[1]*a[1]; cubesOfA[2] = a[2]*a[2]*a[2]; cubesOfA[3] = a[3]*a[3]*a[3]; cubesOfA[4] = a[4]*a[4]*a[4]; ``` ### Object Объект. Сложная структура данных, которая в одной переменной может объединять данные других типов и операции над ними. Будет рассмотрена подробнее на следующих занятиях. ```javascript var person = { name: "Ivan", surname: "Ivanov", age: 25 } ``` Доступ к полям происходит через `.` или через `[]` по строковому ключу: ```javascript person["name"] person.surname ``` > Сформируйте объект с массивами и массив с объектами с осмысленными данными. ### `undefined` Если что-то в Javascript не определено, то это, обычно, `undefined`: ```javascript var a; //значение a - undefined ``` `undefined` - это и тип, и единственное его значение. ### `null` `null` - в целом аналогичен `undefined`, но предназначен для использования его программистом. Т. е. если вы хотите пометить переменную как *пустую* - используйте `null` ## `typeof` позволяет узнать тип в виде строки ## Операции сравнения Каждое выражение можно сравнивать с другим выражением: ### Равенство ```javascript 1 == 2 1 != 2 1 == 1 1 != 1 "text" == 5 "text" != 5 "text" == "Text" "text" == "text" true == "true" true == false false == 0 false === 0 "" == false "" !== false ``` Равенства деляться на строгие (`===`) и нестрогие (`==`): - Строгое сравнение сравнивают по **типу** и **значению**. - Нестрогое сравнение сравнивает по **приведенному** значению. Обычно в таком случае **JS** приводит к числу, а потом сравнивает два числа: ```javascript false == "0" ``` ### Больше, меньше... ```javascript 5 > 6 6 > 5 5.0 >= 5 "a" < "b" "b" <= "a" ``` Результатом таких выражений является значение типа `Boolean`, то есть `true` или `false` ## Условные операторы ### `if` `else` Любое значение, которое может быть приведено к типу `Boolean` может стать условием для условного оператора `if-else`: **Синтаксис:** ```javascript if (cond){ //if cond is true } else { //if cond is false } ``` **Например:** ```javascript var age = prompt("Сколько вам лет?",""); if (+age < 18){ alert("Рано вам еще"); } else { alert("Смотрите на здоровье"); } ``` #### `{}` Код, заключенный в фигурные скобки называется **блоком кода**. В зависимости от условия, он выполняется или невыполняется *последовательно* и *целиком*. Таким образом, фигурные скобки указывают интерпретатору, где начинается и где заканчивается блок кода для выполнения или не выполнения. #### `if`, Краткие формы, выстрел в ногу и `;` ```javascript //если у вас ОДИН оператор в блоке if или else, вы можете не использовать фигурные скобки: if (+age < 18) alert("Рано вам еще"); else alert("Смотрите на здоровье"); //но учтите: ";" - тоже оператор: if (+age < 18) alert("Рано вам еще"); else; alert("Смотрите на здоровье"); //эквивалентно: if (+age < 18) alert("Рано вам еще"); else{ ; } alert("Смотрите на здоровье"); // т.е. последний alert будет срабатывать ВСЕГДА. ``` Ставьте фигурные скобки **всегда**, и избавите себя от лишней траты времени на отладку :-) `if` может быть так же применен без `else`: ```javascript var answer = confirm("будешь кексик?"); if (answer){ alert("кушай на здоровье"); } alert("пока"); ``` ```javascript var age = +prompt("Сколько вам лет?",""); if (age < 18){ alert("школьник"); } else if (age > 18 && age < 30){ alert("молодежь"); } else if (age > 30 && age < 45){ alert("зрелость"); } else if (age > 45 && age < 60){ alert("закат"); } else if (age > 60){ alert("как пенсия?"); } else { alert("то ли киборг, то ли ошибка"); } ``` > Добавьте условие отрицательного возраста в пример выше. Расставьте недостающие (но *синтаксически* необязательные) фигурные скобки. ```javascript var str = prompt("Поговори со мной!!!!",""); if (str){ alert("Ты такой милый " + str); } else { alert("Козёл!!!!!11"); } ``` ### Тернарный оператор Данный оператор позволяет сократить пару `if-else` в некоторых ситуациях: ```javascript var text = confirm("Нажмите что-нибудь") ? "Вы нажали Yes" : "Вы нажали No"; alert(text); var text = confirm("Да, Нет, Наверное") ? "Да" : (confirm ("Нет или Наверное?") ? "Нет" : "Наверное") // вложенный тернарный оператор alert(text); ``` **Принципиально отличие** тернарного оператора от `if`-`else` заключается в том, что тернарный оператор является **выражением**. ### `switch` `switch` позволяет выполнять определенные блоки кода в зависимости от значения выражения: ```javascript var color = prompt("Введите цвет",""); switch (color){ case "red": document.write("
красный
"); break; case "black": document.write("
черный
"); break; case "blue": document.write("
синий
"); break; case "green": document.write("
зеленый
"); break; default: document.write("
Я не понял
"); } ``` `break` в `switch` обеспечивает переход на конец конструкции `switch` (т. е. на код, следущий за `}`). Если `break` не поставить, то можно объединить несколько `case` в один: > Перепишите пример выше, используя `if-else` ```javascript var color = prompt("Введите цвет",""); switch (color){ case "red": document.write("
красный
"); case "black": document.write("
черный
"); break; case "blue": document.write("
синий
"); case "green": document.write("
зеленый
"); break; default: document.write("
Я не понял
"); } ``` В примере выше "red" будет рисовать и "red" и "black", "blue" так же объединится с "green". Однако "black" и "green" будут работать так же как и ранее. **Замечание**: в силу особенностей реализации запуска кода со страницы, пара примеров выше не работают без копипасты в консоль. ## Логические операторы ![Триединость приведения типов](TrinityOfJS.jpg) #### **Не** `!` ```javascript 5 == 5 5 != 5 !true !false !(5 == 5) !(5 != 5) !!0 ``` Как видите, **не** позволяет инвертировать булево значение. *Двойное не* позволяет получить *приведенное к типу* `Boolean` значение переменной. #### **Или** `||` **Или** позволяет объединять несколько булевых значений в одно, по следующей логике: **Если A или B истинно**, то результат - истина. Иначе - результат ложный: ```javascript var isDrunk = isDrunkByBeer || isDrunkByVodka //если пили или водку, или пиво, все равно пьяные :-) var isFlyable = isFly || isBird || isAircraft || isBatman || isSuperman //что-то может летать, если это нечто - самолет, муха или птица, не важно что это. ``` Таблица истинности: | A | B | результат | | ------ | ----- | --- | | false | false | false | | **true** | false | **true** | | false | **true** | **true** | | **true** | **true** | **true** | #### **И** `&&` **И** требует что бы ВСЕ операнды были истинны, иначе результат ложен: ```javascript var isBodun = isDrunkByBeer && isDrunkByVodka //если пили и водку, и пиво, то бодун :-) var isYoung = age > 16 && age < 30 // человек молод от 16 до 30. ``` Таблица истинности: | A | B | | | ------ | ----- | --- | | false | false | false | | **true** | false | false | | false | **true** | false | | **true** | **true** | **true** | ### Порядок выполнения логических выражений Логические выражения выполняются *оптимальным способом* слева направо. То есть, если в **ИЛИ** попался `true`, то следующая часть выражения даже не будет обрабатываться, так как результат уже `true`. **ИЛИ** ищет `true`, и, когда находит, экономит ресурсы компьютера, *сразу же* возвращая true как результат выражения. ```javascript confirm('a') || confirm('b') ``` **И**, напротив, "ищет" `false`. То есть, если найден `false`, то нет смысла далее обрабатывать выражение - оно, так или иначе, будет `false`. ```javascript confirm('a') && confirm('b') ``` Учтите, что `||` и `&&` возвращают **не** `true` или `false` (значение булевского типа), а значения подвыражения как оно есть: Как `false` интерпретируются: - `false` - `0` // 0 как число - `""` //пустая строка - `null` - `undefined` - `NaN` Как `true` интерпретируются все остальные значения, в том числе: - `Infinity` - `-Infinity` - `"0"` //строка не пуста. однако +"0" уже 0 как число, а значит false - `{}` //пустой объект - всё равно `true` - `[]` //пустой массив `[] == false`, но в остальных случаях работает как true **Для проверки используйте** `!!`, двойное отрицание: `!!null` равен `false`, таким образом мы можем почти всегда проверить как интерпретируется то или иное значение. В общем случае объект является `true`, за исключением `null` и `[] == false` ```javascript 2 1+1 2*1 // bool type cast !!2 !!0 !!1 // or 2 || 1 2 || 0 //and 2 && 1 1 && 2 0 && 2 // or and and difference 0 || 1 || 2 0 && 1 && 2 2 || 1 || 0 2 && 1 && 0 confirm('left') || confirm('right') confirm('left') && confirm('right') //null, undefined, so on null || 2 undefined && 1 alert("Hello") && confirm('Are you sexy?'); alert("Hello") || confirm('Are you drunk?'); //brackets and complex expressions (undefined || 2) && (2 || 0) (2 && 1) || (null && 0) (2 > 1) && "greater" (2 < 1) && null null && (2 < 1) // ternary operator 1 ? "one" : "not one" 0 ? "zero" : "not zero" "0" ? "\"zero\"" : "not `zero`" parseInt("0") ? 'true' : 'false' ("" || 2) && (3 || "3.5") || (4 && 5) (-1 + 1) && "zero" "-1" + 1 && "oups" (typeof null === 'object') ? "null is object" : "null is null" // ternary && || Math.random() < 0.5 && 'less' || 'more' (a = Math.random()) < 0.5 && 'less: '+a || 'more: '+a //in for array [2,3,5,7,11].indexOf(7) > -1 ? 'prime' : 'not found' 'random' in Math 'indexOf' in [] var a = b = c = d = 5; ``` ## Запятая *TODO* ## Разделяй и властвуй Для лучшего понимания процесса отладки и написания кода, вы должны понимать, что каждая операция в коде отделена от других, вся связь происходит через данные в переменных. Таким образом для отладки вы можете внедрится в каждую часть кода, убедится в правильности работы этой части, подставив те или иные значения переменных, исправить баги, и быть спокойным конкретно за эту часть в дальнейшем. Каждое корректное выражение может быть частью другого выражения. Вычисление выражений происходит согласно приоритетам операций и вложенности. > Напишите бессмысленное выражение, используя максимум усвоенных на текущий момент знаний. ## Пунктуация в коде. Пунктуация в коде - это отступы. Обычно каждый вложенный **блок кода** должен быть сдвинут вправо на 4 пробела. Современные **IDE** неплохо справляются с этой задачей, так что, скорее всего, просто не мешайте им.