Skip to content

3. Основи JavaScript

Примітка: надалі термін [Javascript] завжди означатиме стандарт ECMAScript 6.

У рамках попереднього проєкту JavaScript створіть папку [bases]. У ній ми розмістимо приклади з цього розділу:

Image

3.1. скрипт [bases-01]

Для ознайомлення з основами PHP7 ми використовували такий код (див. параграф із посиланням):


<?php

// це коментар
// змінна, що використовується без оголошення
$nom = "dupont";
// виведення на екран
print "nom=$nom\n";
// масив з елементами різних типів
$tableau = array("un", "deux", 3, 4);
// кількість елементів
$n = count($tableau);
// цикл
for ($i = 0; $i < $n; $i++) {
  print "tableau[$i]=$tableau[$i]\n";
}
// ініціалізація 2 змінних вмістом масиву
list($chaine1, $chaine2) = array("chaine1", "chaine2");
// об'єднання двох рядків
$chaine3 = $chaine1 . $chaine2;
// виведення результату
print "[$chaine1,$chaine2,$chaine3]\n";
// використання функції
affiche($chaine1);
// тип змінної може бути відомим
afficheType("n", $n);
afficheType("chaine1", $chaine1);
afficheType("tableau", $tableau);
// тип змінної може змінюватися під час виконання
$n = "a changé";
afficheType("n", $n);
// функція може повертати результат
$res1 = f1(4);
print "res1=$res1\n";
// функція може повертати масив значень
list($res1, $res2, $res3) = f2();
print "(res1,res2,res3)=[$res1,$res2,$res3]\n";
// ці значення можна було б зберегти у масиві
$t = f2();
for ($i = 0; $i < count($t); $i++) {
  print "t[$i]=$t[$i]\n";
}
// тести
for ($i = 0; $i < count($t); $i++) {
  // виводить лише рядки
  if (getType($t[$i]) === "string") {
    print "t[$i]=$t[$i]\n";
  }
}
// оператори порівняння == та ===
if("2"==2){
  print "avec l'opérateur ==, la chaîne 2 est égale à l'entier 2\n";
}else{
  print "avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2\n";
}
if("2"===2){
  print "avec l'opérateur ===, la chaîne 2 est égale à l'entier 2\n";
}
else{
  print "avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2\n";
}
// інші тести
for ($i = 0; $i < count($t); $i++) {
  // виводить лише цілі числа >10
  if (getType($t[$i]) === "integer" and $t[$i] > 10) {
    print "t[$i]=$t[$i]\n";
  }
}
// цикл while
$t = [8, 5, 0, -2, 3, 4];
$i = 0;
$somme = 0;
while ($i < count($t) and $t[$i] > 0) {
  print "t[$i]=$t[$i]\n";
  $somme += $t[$i];   //$somme=$somme+$t[$i]
  $i++;               //$i=$i+1
}//while
print "somme=$somme\n";

// кінець програми
exit;

//----------------------------------
function affiche($chaine) {
  // виводить $chaine
  print "chaine=$chaine\n";
}

//виводить
//----------------------------------
function afficheType($name, $variable) {
  // виводить тип $variable
  print "type[variable $" . $name . "]=" . getType($variable) . "\n";
}

//afficheType
//----------------------------------
function f1($param) {
  // додає 10 до $param
  return $param + 10;
}

//----------------------------------
function f2() {
  // повертає 3 значення
  return array("un", 0, 100);
}
?>

У перекладі на JavaScript це дає такий код:


'use strict';
// це коментар
// константа
const nom = "dupont";
// виведення на екран
console.log("nom : ", nom);
// масив з елементами різних типів
const tableau = ["un", "deux", 3, 4];
// кількість елементів
let n = tableau.length;
// цикл
for (let i = 0; i < n; i++) {
  console.log("tableau[", i, "] = ", tableau[i]);
}
// ініціалізація 2 змінних вмістом масиву
let [chaine1, chaine2] = ["chaine1", "chaine2"];
// об'єднання двох рядків
const chaine3 = chaine1 + chaine2;
// виведення результату
console.log([chaine1, chaine2, chaine3]);
// використання функції
affiche(chaine1);
// тип змінної може бути відомим
afficheType("n", n);
afficheType("chaine1", chaine1);
afficheType("tableau", tableau);
// тип змінної може змінюватися під час виконання
n = "a changé";
afficheType("n", n);
// функція може повертати результат
let res1 = f1(4);
console.log("res1=", res1);
// функція може повертати масив значень
let res2, res3;
[res1, res2, res3] = f2();
console.log("(res1,res2,res3)=", [res1, res2, res3]);
// ці значення можна було б зберегти у масиві
let t = f2();
for (let i = 0; i < t.length; i++) {
  console.log("t[i]=", t[i]);
}
// тести
for (let i = 0; i < t.length; i++) {
  // виводить лише рядки
  if (typeof (t[i]) === "string") {
    console.log("t[i]=", t[i]);
  }
}
// оператори порівняння == та ===
if ("2" == 2) {
  console.log("avec l'opérateur ==, la chaîne 2 est égale à l'entier 2");
} else {
  console.log("avec l'opérateur ==, la chaîne 2 n'est pas égale à l'entier 2");
}
if ("2" === 2) {
  console.log("avec l'opérateur ===, la chaîne 2 est égale à l'entier 2");
} else {
  console.log("avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2");
}
// інші тести
for (let i = 0; i < t.length; i++) {
  // відображає лише цілі числа, більші за 10
  if (typeof (t[i]) === "number" && Math.floor(t[i]) === t[i] && t[i] > 10) {
    console.log("t[i]=", t[i]);
  }
}
// цикл while
t = [8, 5, 0, -2, 3, 4];
let i = 0;
let somme = 0;
while (i < t.length && t[i] > 0) {
  console.log("t[i]=", t[i]);
  somme += t[i];
  i++;
}
console.log("somme=", somme);

// програма зупиняється, оскільки більше немає коду для виконання

//виводить
//----------------------------------
function affiche(chaine) {
  // виводить рядок
  console.log("chaine=", chaine);
}

//afficheType
//----------------------------------
function afficheType(name, variable) {
  // виводить тип змінної
  console.log("type[variable ", name, "]=", typeof (variable));
}

//----------------------------------
function f1(param) {
  // додає 10 до параметра
  return param + 10;
}

//----------------------------------
function f2() {
  // повертає 3 значення
  return ["un", 0, 100];
}

Проаналізуємо відмінності між кодами PHP та ECMAScript 6 з оголошенням [use strict] (рядок 1):

  • перша відмінність полягає в тому, що в ECMAScript змінні оголошуються за допомогою таких ключових слів:
    • [let] — для оголошення змінної, значення якої може змінюватися під час виконання коду;
    • [const] — для оголошення змінної, значення якої не змінюватиметься (тобто константи) під час виконання коду;
    • також можна використовувати ключове слово [var] замість [let]. Це ключове слово використовувалося разом із ECMAScript 5. У цьому курсі ми його не використовуватимемо;
  • рядок 6: метод виведення [console.log] може виводити всі типи даних: рядки, числа, логічні значення, масиви, об’єкти. Метод PHP [print] не підтримує вбудованого виведення масивів та об’єктів. У виразі [console.log] [console] є об’єктом, а [log] — методом цього об’єкта;
  • рядок 8: масиви JavaScript — це об’єкти, на які вказує покажчик. Коли ми пишемо:

const tableau = ["un", "deux", 3, 4];

змінна [tableau] є покажчиком на літеральний масив ["un", "deux", 3, 4]. Зміна вмісту масиву не змінює його покажчика. Тому масив найчастіше оголошується за допомогою ключового слова [const]. У PHP масив не позначається покажчиком. Це літеральний масив;

  • рядок 12: змінна циклу [i] оголошується (let) у циклі. Ключове слово [let] дотримується області дії блоку (код між фігурними дужками). Таким чином, змінна [i] у рядку 12 відома лише в циклі;
  • рядок 18: оператор об’єднання рядків — це оператор «+» у JavaScript, а в PHP — «.». Особливістю цього оператора є те, що він має пріоритет над оператором додавання «+». Отже:
    • у PHP ‘1’ + 2 дає число 3;
    • у JavaScript ‘1’+2 дає рядок ‘12’;
  • рядок 20: [console.log] вміє відображати масиви;
  • рядок 82: у JavaScript неможливо вказати тип параметрів функції;
  • рядок 91: оператор [typeof] дозволяє визначити тип даних. Їх є чотири: число, рядок, логічне значення та об’єкт. Зазначимо, що в JavaScript немає ні типу [integer], ні типу [tableau]. Як уже зазначалося, масиви обробляються за допомогою покажчиків і належать до категорії об’єктів;
  • рядки 50–59: як і в PHP, у JavaScript є два оператори порівняння — == та ‘===’ — з тим самим значенням, що й у PHP. ESLint найчастіше вказує на оператор == як на можливу помилку. Слід систематично використовувати оператор ‘===’;
  • рядок 79: можна було б вказати інструкцію [return], але ESLint видає попередження про те, що [return] слід використовувати лише у функції;

Виконаємо цей код:

Image

Результати виконання:


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-01.js"
nom : dupont
tableau[ 0 ] = un
tableau[ 1 ] = deux
tableau[ 2 ] = 3
tableau[ 3 ] = 4
[ 'chaine1', 'chaine2', 'chaine1chaine2' ]
chaine= chaine1
type[variable n ]= number
type[variable chaine1 ]= string
type[variable tableau ]= object
type[variable n ]= string
res1= 14
(res1,res2,res3)= [ 'un', 0, 100 ]
t[ 0 ]= un
t[ 1 ]= 0
t[ 2 ]= 100
t[ 0 ]= un
avec l'opérateur ==, la chaîne 2 est égale à l'entier 2
avec l'opérateur ===, la chaîne 2 n'est pas égale à l'entier 2
t[ 2 ]= 100
t[ 0 ]= 8
t[ 1 ]= 5
somme= 13

[Done] exited with code=0 in 0.316 seconds

У написаному коді ESLINT повідомляє про дві помилки:

Image

  • при наведенні курсору на червоний рядок попередження з’являється повідомлення про помилку [3]. Тут ESLint не розуміє, що порівнюються дві константи. Один з двох операндів повинен бути змінною;
  • у [4] опція [Quick Fix] дозволяє прибрати попередження, якщо ви вирішите не виправляти помилку;

Image

  • у [5] є можливість вимкнути попередження для поточного рядка або для всього файлу. Саме останню опцію ми обираємо тут. Тоді на початку файлу генерується рядок [6];

3.2. скрипт [bases-02]

Скрипт [bases-02] демонструє використання ключових слів [let] та [const]:


'use strict';
// для ініціалізації змінної використовують let або const
// let для змінних
let x = 4;
x++;
console.log(x);
// const — для констант
const y = 10;
x += y;
// заборонено
y++;
  • рядок 11 викликає помилку під час виконання [1-2]. Про неї повідомляє ESLint перед виконанням [3]:

Image

3.3. скрипт [bases-03]

Скрипт [bases-03] перевіряє область дії змінних у JavaScript:


'use strict';
// область дії змінних
let count = 1;
function doSomething() {
  // змінна count тут визначена
  console.log("count=",count);
}
// виклик
doSomething();
  • проте змінна [count], оголошена поза межами функції [doSomething], є доступною в цій функції. Це є принциповою відмінністю від PHP;

Виконання


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-03.js"
count= 1

[Done] exited with code=0 in 0.3 seconds

3.4. скрипт [bases-04]

Локальна змінна приховує глобальну змінну з такою самою назвою:


'use strict';
// область дії змінних
const count = 1;
function doSomething() {
  // локальна змінна приховує глобальну змінну
  const count = 2;
  console.log("count inside function=",count);
}
// глобальна змінна
console.log("count outside function=",count);
// локальна змінна
doSomething();

Виконання


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-04.js"
count outside function= 1
count inside function= 2

[Done] exited with code=0 in 0.246 seconds

3.5. скрипт [bases-05]

Змінна, визначена у функції, не є відомою поза межами цієї функції:


'use strict';
// область дії змінних
function doSomething() {
  // локальна змінна функції
  const count = 2;
  console.log("count inside function=", count);
}
// тут count невідомий
console.log("count outside function=", count);
doSomething();

ESLint повідомляє про помилку в рядку 9:

Image

3.6. скрипт [bases-06]

Ключові слова [let] та [const] визначають змінні з областю дії [bloc] (код у фігурних дужках), але не ключове слово [var]:


'use strict';
// ключове слово [let] дозволяє визначити змінну з областю дії блоку
{
  // змінна [count] відома лише в цьому блоці
  let count = 1;
  console.log("count=", count);
}
// тут змінна [count] невідома
count++;

// ключове слово [const] дозволяє визначити змінну з областю дії блоку
{
  // змінна [count2] відома лише в цьому блоці
  const count2 = 1;
  console.log("count=", count2);
}
// тут змінна [count2] невідома
count2++;

// ключове слово [var] не дозволяє визначити змінну з областю дії блоку
{
  // змінна [count3] буде глобальною
  var count3 = 1;
  console.log("count=", count3);
}
// тут змінна [count3] є визначеною
count3++;

Коментарі

  • рядок 5: змінна [count] відома лише в блоці коду, в якому вона оголошена (рядки 3–7);
  • рядок 14: константа [count2] відома лише в блоці коду, в якому вона оголошена (рядки 12–16);
  • рядок 23: змінна [count3] використовується поза блоком коду, в якому вона оголошена (рядки 21–25);

ESLint повідомляє про такі помилки:

Image

З огляду на ці особливості області дії блоку, надалі ми будемо використовувати лише ключові слова [let] та [const].

3.7. скрипт [bases-07]

Типи даних у JavaScript:


'use strict';

// тип даних jS
const var1 = 10;
const var2 = "abc";
const var3 = true;
const var4 = [1, 2, 3];
const var5 = {
  nom: 'axèle'
};
const var6 = function () {
  return +3;
}
// виведення типів
console.log("typeof(var1)=", typeof (var1));
console.log("typeof(var2)=", typeof (var2));
console.log("typeof(var3)=", typeof (var3));
console.log("typeof(var4)=", typeof (var4));
console.log("typeof(var5)=", typeof (var5));
console.log("typeof(var6)=", typeof (var6));

Виконання


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Temp\19-09-01\javascript\bases\bases-07.js"
typeof(var1)= number
typeof(var2)= string
typeof(var3)= boolean
typeof(var4)= object
typeof(var5)= object
typeof(var6)= function

[Done] exited with code=0 in 0.26 seconds

Коментарі

  • рядок 7 (код): масив є об’єктом. Отже, [var4] є покажчиком на масив, а не самим масивом;
  • рядок 8 (код): [var5] — це покажчик на літеральний об’єкт. Ми побачимо, що літеральні об’єкти в JavaScript дуже схожі на екземпляри класу PHP. На них також посилаються за допомогою покажчиків;
  • рядок 11 (код): змінна може бути типу [fonction] (рядок 7 результатів);

3.8. скрипт [bases-08]

Цей скрипт демонструє можливі зміни типів у JavaScript.


'use strict';

// неявні зміни типів
// тип -->bool
console.log("---------------[Conversion implicite vers un booléen]------------------------------");
showBool("abcd");
showBool("");
showBool([1, 2, 3]);
showBool([]);
showBool(null);
showBool(0.0);
showBool(0);
showBool(4.6);
showBool({});
showBool(undefined);

function showBool(data) {
  // перетворення даних у логічне значення відбувається автоматично в наступному тесті
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[valeur booléenne(data)]=", data ? true : false);
}

// неявні зміни типу у числовий т ип
console.log("---------------[Conversion implicite vers un nombre]------------------------------");
showNumber("12");
showNumber("45.67");
showNumber("abcd");

function showNumber(data) {
  // data + 1 не працює, оскільки в цьому випадку jS виконує конкатенацію рядків, а не додавання
  const nombre = data * 1;
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[nombre]=", nombre, "[type(nombre)]=", typeof (nombre));
}

// явні перетворення типів у логічні значення
console.log("---------------[Conversion explicite vers un booléen]------------------------------");
showBool2("abcd");
showBool2("");
showBool2([1, 2, 3]);
showBool2([]);
showBool2(null);
showBool2(0.0);
showBool2(0);
showBool2(4.6);
showBool2({});
showBool2(undefined);

function showBool2(data) {
  // перетворення data у логічне значення відбувається явно в наступному тесті
  console.log("[", data, "], [type(data)]=", typeof (data), "[valeur booléenne(data)]=", Boolean(data));
}
// явні зміни типу на числовий
console.log("---------------[Conversion explicite vers un nombre]------------------------------");
showNumber2("12.45");
showNumber2(67.8);
showNumber2(true);
showNumber2(null);

function showNumber2(data) {
  const nombre = Number(data);
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[nombre]=", nombre, "[type(nombre)]=", typeof (nombre));
}

// у тип String
console.log("---------------[Conversion explicite vers un string]------------------------------");
showString(5);
showString(6.7);
showString(false);
showString(null);

function showString(data) {
  const chaîne = String(data);
  console.log("[data=", data, "], [type(data)]=", typeof (data), "[chaîne]=", chaîne, "[type(chaîne)]=", typeof (chaîne));
}

// деякі несподівані неявні перетворення
console.log("---------------[Autres cas]------------------------------");
const string1 = '1000.78';
// об'єднання рядків за замовчуванням
const data1 = string1 + 1.034;
console.log("data1=", data1, "type=", typeof (data1));
const data2 = 1.034 + string1;
console.log("data2=", data2, "type=", typeof (data2));
// явне перетворення у число
const data3 = Number(string1) + 1.034;
console.log("data3=", data3, "type=", typeof (data3));
// true перетворюється на число 1
const data4 = true * 1.18;
console.log("data4=", data4, "type=", typeof (data4));
// false перетворюється на число 0
const data5 = false * 1.18;
console.log("data5=", data5, "type=", typeof (data5));

Виконання


[Running] C:\myprograms\laragon-lite\bin\nodejs\node-v10\node.exe "c:\Data\st-2019\dev\es6\javascript\bases\bases-08.js"
---------------[Conversion implicite vers un booléen]------------------------------
[data= abcd ], [type(data)]= string [valeur booléenne(data)]= true
[data= ], [type(data)]= string [valeur booléenne(data)]= false
[data= [ 1, 2, 3 ] ], [type(data)]= object [valeur booléenne(data)]= true
[data= [] ], [type(data)]= object [valeur booléenne(data)]= true
[data= null ], [type(data)]= object [valeur booléenne(data)]= false
[data= 0 ], [type(data)]= number [valeur booléenne(data)]= false
[data= 0 ], [type(data)]= number [valeur booléenne(data)]= false
[data= 4.6 ], [type(data)]= number [valeur booléenne(data)]= true
[data= {} ], [type(data)]= object [valeur booléenne(data)]= true
[data= undefined ], [type(data)]= undefined [valeur booléenne(data)]= false
---------------[Conversion implicite vers un nombre]------------------------------
[data= 12 ], [type(data)]= string [nombre]= 12 [type(nombre)]= number
[data= 45.67 ], [type(data)]= string [nombre]= 45.67 [type(nombre)]= number
[data= abcd ], [type(data)]= string [nombre]= NaN [type(nombre)]= number
---------------[Conversion explicite vers un booléen]------------------------------
[ abcd ], [type(data)]= string [valeur booléenne(data)]= true
[ ], [type(data)]= string [valeur booléenne(data)]= false
[ [ 1, 2, 3 ] ], [type(data)]= object [valeur booléenne(data)]= true
[ [] ], [type(data)]= object [valeur booléenne(data)]= true
[ null ], [type(data)]= object [valeur booléenne(data)]= false
[ 0 ], [type(data)]= number [valeur booléenne(data)]= false
[ 0 ], [type(data)]= number [valeur booléenne(data)]= false
[ 4.6 ], [type(data)]= number [valeur booléenne(data)]= true
[ {} ], [type(data)]= object [valeur booléenne(data)]= true
[ undefined ], [type(data)]= undefined [valeur booléenne(data)]= false
---------------[Conversion explicite vers un nombre]------------------------------
[data= 12.45 ], [type(data)]= string [nombre]= 12.45 [type(nombre)]= number
[data= 67.8 ], [type(data)]= number [nombre]= 67.8 [type(nombre)]= number
[data= true ], [type(data)]= boolean [nombre]= 1 [type(nombre)]= number
[data= null ], [type(data)]= object [nombre]= 0 [type(nombre)]= number
---------------[Conversion explicite vers un string]------------------------------
[data= 5 ], [type(data)]= number [chaîne]= 5 [type(chaîne)]= string
[data= 6.7 ], [type(data)]= number [chaîne]= 6.7 [type(chaîne)]= string
[data= false ], [type(data)]= boolean [chaîne]= false [type(chaîne)]= string
[data= null ], [type(data)]= object [chaîne]= null [type(chaîne)]= string
---------------[Autres cas]------------------------------
data1= 1000.781.034 type= string
data2= 1.0341000.78 type= string
data3= 1001.814 type= number
data4= 1.18 type= number
data5= 0 type= number