Към съдържанието

2. Variables, типове и оператори ​

Занятие 2упражнения: 02-variables-and-types/ в homework repositorydoc: примерният JSON документ

Днес ще се научите да:

  • декларирате variables с let и const и да им давате добри имена;
  • разпознавате примитивните типове и да проверявате типа на стойност с typeof;
  • смятате с числа и да съставяте текст със strings;
  • превръщате strings от JSON отчета в numbers и booleans.

Къде е мястото на тази тема в примерното правило за проверка - днес можем да напишем маркираните редове:

js
function rule(doc) {
    const library = require("library.js");

    let name = String(doc.inventory?.extended_info?.json?.data?.system?.name
                      || doc.status.device_alias);
    let serial = doc.overview.serial_number;
    let model = doc.overview.model;
    let version = doc.overview.version;

    if (["XR-210", "XR-220"].includes(doc.overview.model)
        && !library.version_below(doc.overview.version, "4.2.1.7")) {
        emit(doc.status.device_alias, { /* ... alert details ... */ });
    }
}

1. Деклариране и дефиниране на variables ​

Variable е име за стойност в паметта. Създаването ѝ има две части:

  • деклариране - казваме на JavaScript името: let serial;
  • дефиниране (инициализиране) - даваме ѝ първата стойност: serial = "SN4X7Q92";

Обикновено правим двете наведнъж:

js
let serial;                 // declared, but has no value yet
console.log(serial);        // undefined

serial = "SN4X7Q92";        // now defined
console.log(serial);

let model = "XR-220";       // declared and defined at once
console.log(model);
Променете кода и го изпълнете отново

let и const ​

MDN: let, const

Ключова думаМоже ли да получи нова стойност?За какво се ползва
constнестойности, които не се променят - повечето ви variables
letдаброячи, резултати, които се натрупват стъпка по стъпка
varдасамо в стар код - не го използвайте в нов код
js
const model = "XR-220";
let checkedSystems = 0;

checkedSystems = checkedSystems + 1;   // fine, it is a let
console.log(checkedSystems);

model = "XR-210";                      // error: model is a const
console.log("this line never runs");
Променете кода и го изпълнете отново

Започвайте с const

Пишете const по подразбиране. Сменете го с let само когато наистина трябва да дадете нова стойност на variable. Добрите насоки за правилата искат същото за глобалните variables: "they must be declared as const".

Анимация

Variables в паметта: 5. const

Strict mode: без случайни variables ​

MDN: Strict mode

Без let, const или var JavaScript тихо създава глобална variable. Тогава печатна грешка в името създава нова variable, вместо да даде грешка:

js
let firmwareLevel = "4.2.1.7";
firmwarelevel = "4.3.0.0";      // typo: small "l" - a new global variable!
console.log(firmwareLevel);     // still 4.2.1.7
Променете кода и го изпълнете отново

Сложете "use strict"; като първи ред на файла (или на функцията) и същата грешка вече спира програмата:

js
"use strict";
let firmwareLevel = "4.2.1.7";
FirmwareLevel = "4.3.0.0";      // typo: capital "F" - now an error
console.log(firmwareLevel);
Променете кода и го изпълнете отново

ИНФОРМАЦИЯ

Модулите и класовете винаги са в strict mode. Във файловете за упражнения започваме с "use strict";.

Анимация

Scope на variables: 4. Без деклариране и "use strict"

2. Имена на variables ​

Правила (иначе: синтактична грешка):

  • букви, цифри, _ и $; без интервали, без -;
  • не може да започва с цифра;
  • не може да е запазена дума (let, const, if, function, class, ...);
  • имената различават малки и главни букви: model, MODEL и Model са три различни variables.

Конвенции (добра практика):

  • camelCase за variables: serialNumber, firmwareLevel, isAffected;
  • имена, които казват какво има вътре: firmwareLevel, а не x или data2;
  • имената на booleans започват с is, has, can: isEnabled, hasCert;
  • UPPER_SNAKE_CASE за фиксирани настройки: const MIN_FIRMWARE_LEVEL = "4.2.1.7";

Ключове в JSON срещу имена на variables

Ключовете в JSON отчета са в snake_case (firmware_level, remote_login_enabled). Така са кръстени данните - оставете ключовете както са. Вашите собствени variables са в camelCase: const firmwareLevel = doc.inventory.details.firmware_level;

Проверете се: кои от тези имена са валидни?

serial_number, 2ndNode, firmware-level, $total, const, isRemote, MODEL

Отговор

Валидни: serial_number, $total, isRemote, MODEL. Невалидни: 2ndNode (започва с цифра), firmware-level (- е минус), const (запазена дума).

3. Примитивни типове ​

MDN: JavaScript data types and data structures

Една стойност в JavaScript е или примитивна (една проста стойност), или обект (структура с properties - като doc). Примитивните типове:

ТипПримериВ данните на отчета
number42, 9.1, -3, 1_000_000бройки, размери (след преобразуване)
string"XR-220", 'yes', `text`почти всяка стойност
booleantrue, false"yes" / "no" след преобразуване
undefinedundefinedключ, който го няма в документа
nullnull"няма стойност", записано нарочно

(Има още два - bigint и symbol, но рядко трябват.)

typeof ​

MDN: typeof

js
console.log(typeof 42);              // number
console.log(typeof "4.2.1.7");       // string
console.log(typeof true);            // boolean
console.log(typeof undefined);       // undefined
console.log(typeof null);            // object  - a famous old bug in JavaScript
console.log(typeof doc);             // object
Променете кода и го изпълнете отново

Numbers ​

Целите и дробните числа са от един и същ тип - number:

js
const nodes = 2;
const ratio = 0.75;
const capacityBytes = 2_199_023_255_552;   // "_" only makes it readable

console.log(nodes, ratio, capacityBytes);
console.log(0.1 + 0.2);                    // not exactly 0.3!
console.log(10 / 0);                       // Infinity
Променете кода и го изпълнете отново

Дробните числа не са точни

0.1 + 0.2 дава 0.30000000000000004. Числата се пазят в двоичен вид, затова повечето дробни числа са приближения. Закръглявайте резултатите, преди да ги покажете.

Strings ​

MDN: String, Template literals

Три вида кавички:

js
const a = "double quotes";
const b = 'single quotes';
const c = `backticks: a template string`;
console.log(a);
console.log(b);
console.log(c);
Променете кода и го изпълнете отново

Escape последователности - специални символи в string:

js
console.log("Name:\tLAB-DEV-01");         // \t  tab
console.log("line 1\nline 2");            // \n  new line
console.log("the \"Version\" column");    // \"  a quote inside a string
console.log("C:\\checks\\rules");         // \\  a backslash
Променете кода и го изпълнете отново

Template strings (с обратни кавички) могат да са на няколко реда и вмъкват стойности с ${...} - много удобно за съобщенията на alert:

js
const name = "LAB-DEV-01";
const model = "XR-220";
const firmwareLevel = "4.2.1.7";

const message = `System ${name} (${model}) runs firmware level ${firmwareLevel}.`;
console.log(message);
Променете кода и го изпълнете отново

undefined и null ​

  • undefined - "тук нищо не е сложено": декларирана variable без стойност или ключ, който го няма в документа.
  • null - "няма стойност", зададено нарочно.
js
console.log(doc.overview.model);      // the key exists
console.log(doc.overview.nickname);   // no such key: undefined
Променете кода и го изпълнете отново

Ето защо правилата проверяват за липсващи данни

Четенето на липсващ ключ дава undefined. Четенето на ключ от undefined е грешка - точно от това пази ?. в примерното правило (занятие 6).

Анимация

Variables в паметта: 4. Типове стойности

4. Коментари ​

js
// a one-line comment

/*
   a comment over
   several lines
*/

/**
 * A documentation comment (JSDoc) - describes the code below it.
 * A rule template usually starts with one.
 */

Пишете коментари, които обясняват защо, а не какво: // rule guidelines require const globals е полезен; // set x to 5 не е.

5. Оператори ​

Присвояване ​

= слага стойността отдясно в variable отляво. Кратки форми:

js
let alerts = 0;
alerts = alerts + 1;   // 1
alerts += 2;           // same as alerts = alerts + 2   -> 3
alerts -= 1;           // 2
alerts *= 10;          // 20
alerts++;              // add 1 -> 21
alerts--;              // subtract 1 -> 20
console.log(alerts);
Променете кода и го изпълнете отново

Анимации

Variables в паметта: 3. x = x ** 2

Как се изчислява един израз: 3. Присвояването е израз, 4. i++ и ++i

Аритметика ​

ОператорЗначениеПримерРезултат
+ - * /както в математиката7 / 23.5
%остатък7 % 21
**степен2 ** 101024

Пример с дисково пространство - от байтове в TiB (1 TiB = 10244 байта):

js
const capacityBytes = 2_199_023_255_552;
const usedBytes = 1_517_325_046_333;

const capacityTiB = capacityBytes / 1024 ** 4;
const usedPercent = usedBytes / capacityBytes * 100;

console.log(capacityTiB);                   // 2
console.log(usedPercent);                   // many decimals
console.log(Math.round(usedPercent));       // 69
console.log(usedPercent.toFixed(1));        // 69.0 - a string with 1 decimal
Променете кода и го изпълнете отново

Приоритет ​

MDN: Operator precedence

Както в математиката: първо **, после * / %, после + -. Когато се колебаете, слагайте скоби:

js
console.log(2 + 3 * 4);       // 14
console.log((2 + 3) * 4);     // 20
console.log(100 - 60 / 2);    // 70
Променете кода и го изпълнете отново

Проверете се: какво извежда 10 + 20 / 10 * 2 ** 2?

Отговор

18: първо 2 ** 2 = 4, после 20 / 10 = 2, 2 * 4 = 8, после 10 + 8.

Анимации

Как се изчислява един израз: 1. Приоритет, 2. Асоциативност, 5. Ред на изчисляване (advanced)

6. Strings и numbers заедно ​

+ със string съединява (конкатенира). Останалите аритметични оператори превръщат strings в numbers:

js
console.log("9" + 1);         // 91  - joined
console.log("9" - 1);         // 8   - subtracted
console.log("3" * "4");       // 12
console.log(1 + 2 + "3");     // 33  - left to right: 3, then "3" + "3"
console.log("1" + 2 + 3);     // 123
Променете кода и го изпълнете отново

ВНИМАНИЕ

"9" + 1 е "91", а не 10. Когато стойностите идват от JSON, първо ги преобразувайте, после смятайте.

Анимация

Типове, сравнения и логика: 1. Операторът +

7. Преобразуване на стойности ​

Стойностите в JSON отчета са strings ​

js
const version = doc.overview.version;
const enabled = doc.inventory.details.remote_login_enabled;
const epoch = doc.status.epoch;

console.log(version, typeof version);
console.log(enabled, typeof enabled);
console.log(epoch, typeof epoch);
Променете кода и го изпълнете отново

От string към number ​

MDN: Number() constructor, parseInt(), parseFloat()

js
console.log(Number("42"));            // 42
console.log(Number(" 42 "));          // 42 - spaces around are ignored
console.log(Number(""));              // 0  - careful!
console.log(Number("4.2.1.7"));       // NaN - Not a Number
console.log(parseInt("4.2.1.7"));     // 4   - reads digits until it cannot
console.log(parseFloat("4.2.1.7"));   // 4.2
console.log(parseInt("8 nodes"));     // 8
Променете кода и го изпълнете отново
  • Number(x) - целият string трябва да е число, иначе NaN.
  • parseInt(x) / parseFloat(x) - четат от началото, докъдето могат.
  • NaN е number, който означава "невалидно число". Проверявайте го с Number.isNaN(value).

Версията не е число

"4.2.1.7" има четири части. Number дава NaN, parseFloat дава 4.2 - и двете губят информация. Ще сравняваме версии част по част в занятие 5.

Анимация

Типове, сравнения и логика: 2. От string към number

От number към string ​

js
const nodes = 2;
console.log(String(nodes));           // 2 (a string)
console.log(nodes + "");              // 2 (a string)
console.log(`${nodes}`);              // 2 (a string)
console.log(typeof String(nodes));    // string
Променете кода и го изпълнете отново

Примерното правило обвива името в String(...), така че резултатът винаги е string, каквото и да съдържа JSON.

"yes" / "no" към boolean ​

Сравнявайте с текста, който очаквате - === означава "точно равно на" (повече в занятие 3):

js
const enabledText = doc.inventory.details.remote_login_enabled;   // "yes"
const isEnabled = enabledText === "yes";

console.log(isEnabled);           // true
console.log(typeof isEnabled);    // boolean
Променете кода и го изпълнете отново

От EPOCH към дата ​

EPOCH в отчета е броят секунди от 1 януари 1970 г. (UTC), записан като string. Датите в JavaScript броят милисекунди:

js
const epochSeconds = Number(doc.status.epoch);
const reportDate = new Date(epochSeconds * 1000);

console.log(epochSeconds);
console.log(reportDate.toISOString());
Променете кода и го изпълнете отново

8. Упражнения ​

Отворете във VSCode вашето копие на Homework repository (първия път: вижте Как да ползвате тези страници; преди занятието: git pull --no-rebase --no-edit upstream main) и пускайте задачите от терминала, в основната папка на repository-то:

bash
node 02-variables-and-types/practice/task1-rule-variables.js

Всеки файл обяснява задачата в началото си. Пишете кода си между редовете your code; проверките най-долу извеждат OK или FAIL.

ЗадачаФайлКакво правите
1task1-rule-variables.jsVariables за данните на примерното правило и съобщение за alert с template string
2task2-predict-types.jsПредвидете резултата от 12 израза, после проверете
3task3-capacity.jsБайтове от JSON (strings) в TiB и процент заето място
4task4-report-age.jsПреди колко дни и часа е изпратен един отчет

Обобщение ​

ТемаЗапомнете
Variablesconst по подразбиране, let, когато стойността се променя, никога var; "use strict";
ИменаcamelCase, със смисъл; ключовете в JSON остават каквито са
Типовеnumber, string, boolean, undefined, null; проверка с typeof
Strings"...", '...', `...${value}...`; escape последователности \n, \t, \"
Оператори+ - * / % **, +=, ++; приоритет като в математиката
+ със stringsсъединява: "9" + 1 е "91"
ПреобразуванеNumber(), parseInt(), parseFloat(), String(); NaN; === "yes"

Домашно ​

  1. 02-variables-and-types/homework.js (в homework repository): обобщение за отдалечения вход от стойностите remote_login_*.
  2. Задачите за упражнение, които не сте довършили в час - препоръчително, защото следващите задачи и курсовият проект ги използват отново. Всяка проверка трябва да отпечата OK.
  3. По желание: вземете JSON документ, който познавате (анонимизиран), и опитайте същите преобразувания върху него.

Още за четене ​

Следващото занятие: сравнения, логически оператори, условия и loops - и if от примерното правило.

Създаден за