From 218934fa2ed1c702a6d3923d2aa2cc6b43c48684 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 8 Dec 2020 14:43:23 -0500 Subject: initial commit --- .../control_flow_and_error_handling/index.html | 465 +++++++++++ .../guide/dokladno_pro_objectnu_model/index.html | 760 +++++++++++++++++ files/uk/web/javascript/guide/functions/index.html | 655 +++++++++++++++ .../javascript/guide/grammar_and_types/index.html | 716 ++++++++++++++++ files/uk/web/javascript/guide/index.html | 131 +++ .../guide/indexed_collections/index.html | 578 +++++++++++++ .../web/javascript/guide/introduction/index.html | 147 ++++ .../guide/iterators_and_generators/index.html | 214 +++++ .../guide/loops_and_iteration/index.html | 355 ++++++++ .../javascript/guide/numbers_and_dates/index.html | 383 +++++++++ .../guide/regular_expressions/index.html | 635 ++++++++++++++ .../web/javascript/guide/using_promises/index.html | 363 ++++++++ .../guide/working_with_objects/index.html | 490 +++++++++++ .../index.html" | 925 +++++++++++++++++++++ 14 files changed, 6817 insertions(+) create mode 100644 files/uk/web/javascript/guide/control_flow_and_error_handling/index.html create mode 100644 files/uk/web/javascript/guide/dokladno_pro_objectnu_model/index.html create mode 100644 files/uk/web/javascript/guide/functions/index.html create mode 100644 files/uk/web/javascript/guide/grammar_and_types/index.html create mode 100644 files/uk/web/javascript/guide/index.html create mode 100644 files/uk/web/javascript/guide/indexed_collections/index.html create mode 100644 files/uk/web/javascript/guide/introduction/index.html create mode 100644 files/uk/web/javascript/guide/iterators_and_generators/index.html create mode 100644 files/uk/web/javascript/guide/loops_and_iteration/index.html create mode 100644 files/uk/web/javascript/guide/numbers_and_dates/index.html create mode 100644 files/uk/web/javascript/guide/regular_expressions/index.html create mode 100644 files/uk/web/javascript/guide/using_promises/index.html create mode 100644 files/uk/web/javascript/guide/working_with_objects/index.html create mode 100644 "files/uk/web/javascript/guide/\320\262\320\270\321\200\320\260\320\267\320\270_\321\202\320\260_\320\276\320\277\320\265\321\200\320\260\321\202\320\276\321\200\320\270/index.html" (limited to 'files/uk/web/javascript/guide') diff --git a/files/uk/web/javascript/guide/control_flow_and_error_handling/index.html b/files/uk/web/javascript/guide/control_flow_and_error_handling/index.html new file mode 100644 index 0000000000..c055e31dc0 --- /dev/null +++ b/files/uk/web/javascript/guide/control_flow_and_error_handling/index.html @@ -0,0 +1,465 @@ +--- +title: Управління потоком виконання та обробка помилок +slug: Web/JavaScript/Guide/Control_flow_and_error_handling +translation_of: Web/JavaScript/Guide/Control_flow_and_error_handling +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}
+ +

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

+ +

Довідник JavaScript містить вичерпні дані про інструкції, описані у цьому розділі. Символ крапки з комою (;) розділяє інструкції у JavaScript-коді.

+ +

Будь-який вираз у JavaScript також являється інструкцією. Повну інформацію про вирази дивіться у розділі Вирази та оператори.

+ +

Блокова інструкція

+ +

Найбільш базовою інструкцією є блокова, що об'єднує кілька інструкцій в одну. Блок обмежується парою фігурних дужок:

+ +
{
+  інструкція_1;
+  інструкція_2;
+  .
+  .
+  .
+  інструкція_n;
+}
+
+ +

Приклад

+ +

Блокова інструкція зазвичай використовується поряд з інструкціями для управління потоком виконання (наприклад, if, for, while).

+ +
while (x < 10) {
+  x++;
+}
+
+ +

У даному випадку, { x++; } є блоковою інструкцією.

+ +
+

Важливо: JavaScript до ECMAScript2015 не мав блокової області видимості. Змінні, об'явлені всередині блоку, були видимі в області меж зовнішньої функції або ж усього скрипта. І ефект від їхнього зміни поширювався за межі блоку. Інакше кажучи, блокові інструкції не створювали області видимості.

+ +

"Поодинокі" блоки у JavaScript можуть мати зовсім інші наслідки, ніж у мовах C чи Java. Наприклад:

+ +
var x = 1;
+{
+  var x = 2;
+}
+console.log(x); // в результаті - 2
+
+ +

В результаті отримуємо 2, тому що інструкція var x всередині блоку перебуває в одній області видимості з інструкцією var x перед блоком. У C чи Java подібний код поверне 1.

+ +

Починаючи з ECMAScript2015, декларації змінних let і const мають блокову область видимості. Докладніше на довідкових сторінках {{jsxref("Statements/let", "let")}} і {{jsxref("Statements/const", "const")}}.

+
+ +

Умовні інструкції

+ +

Умовною інструкцією називається набір команд, що виконаються, якщо певна умова буде істинною. JavaScript підтримує два види умовних інструкцій: if...else та switch.

+ +

Інструкція if...else

+ +

Використовуйте if, щоб виконати інструкцію, якщо логічна умова являється істинною. Використовуйте необов'яковий else, щоб виконати інструкцію, якщо умова являється хибною. Інструкція if виглядає так:

+ +
if (умова) {
+  інструкція_1;
+} else {
+  інструкція_2;
+}
+ +

Тут умова може бути будь-яким виразом, що зводиться до true чи false (дивіться розділ Boolean для роз'яснення, що і як обчислюється до true чи false). Якщо умова обчислюється до true, виконується інструкція_1; інакше виконується інструкція_2. інструкція_1 та інструкція_2 можуть бути будь-якими, включаючи вкладені інструкції if.

+ +

Можна також суміщувати інструкції у вигляді else if, щоб послідовно перевірити кілька умов, як-от, наприклад:

+ +
if (умова_1) {
+  інструкція_1;
+} else if (умова_2) {
+  інструкція_2;
+} else if (умова_n) {
+  інструкція_n;
+} else {
+  інструкція_остання;
+}
+
+ +

У випадку наявності кількох таких умов буде виконано лише найперший обчислений до true. Щоб виконати кілька інструкцій, слід об'єднати їх у блок ({ ... }) .

+ +

Найкращі практики

+ +

Загалом, хорошою практикою вважається завжди використовувати блоки інструкцій, особливо при вкладенні інструкцій if:

+ +
if (умова) {
+  інструкція_1_виконується_якщо_умова_правильна;
+  інструкція_2_виконується_якщо_умова_правильна;
+} else {
+  інструкція_3_виконується_якщо_умова_хибна;
+  інструкція_4_виконується_якщо_умова_хибна;
+}
+
+ +
Не рекомендується використовувати звичайні присвоєння в умовних виразах, бо присвоєння можна сплутати з порівнянням при перегляді коду.
+ +
+ +
Наприклад, не слід писати ось так:
+ +
// Ймовірно, буде прочитано як "x == y"
+if (x = y) {
+  /* statements here */
+}
+
+ +

Якщо все ж таки потрібно використати присвоєння всередині умовного виразу, загальною практикою є додавання зайвих дужок навколо присвоєння, як-от:

+ +
if ((x = y)) {
+  /* інструкції тут */
+}
+
+ +

Хибні значення

+ +

Наступні значення обчислюються до false (також знані як {{Glossary("Falsy")}} значення):

+ + + +

Всі інші значення (включно з усіма об'єктами), обчислюються до true при передачі в умовний вираз.

+ +
+

Увага: не плутайте примітивні булеві значення true та false із істинними і хибними значеннями об'єкту {{jsxref("Boolean")}}. Наприклад:

+ +
var b = new Boolean(false);
+if (b) // цей умовний вираз буде істинним
+if (b == true) // цей умовний вираз буде хибним
+
+
+ +

Приклад

+ +

У наведеному далі прикладі функція checkData повертає true, якщо в об'єкті  Text три символи, а інакше вона показує сповіщення та повертає false.

+ +
function checkData() {
+  if (document.form1.threeChar.value.length == 3) {
+    return true;
+  } else {
+    alert('Enter exactly three characters. ' +
+    document.form1.threeChar.value + ' is not valid.');
+    return false;
+  }
+}
+
+ +

Інструкція switch

+ +

Інструкція switch дозволяє програмі оцінити вираз і спробувати співставити значення виразу з міткою case. Якщо відповідність знайдено  , програма виконує пов'язану з цим інструкцію.

+ +

Інструкція switch виглядає наступним чином:

+ +
switch (expression) {
+  case label_1:
+    statements_1
+    [break;]
+  case label_2:
+    statements_2
+    [break;]
+    ...
+  default:
+    statements_def
+    [break;]
+}
+ +

JavaScript розуміє switch інструкцію наступним чином:

+ + + +

Інструкція break

+ +

Необов'язкова інструкція break, пов’язана із кожним пунктом case, забезпечує те, що програма виходить з конструкції switch, якщо виконується відповідна умова, і продовжує виконання інструкцій після конструкції switch. Якщо break не використовується, програма продовжує виконання інструкції наступних пунктів всередині switch, не перевіряючи умови.

+ +
Приклад
+ +

У наступному прикладі, якщо fruittype дорівнює "Bananas", програма виконує пов'язану з пукнтом "Bananas" інструкцію. Коли виникає break, програма припиняє switch та виконує наступну після switch інструкцію. Якщо break б була опущена, інструкції для пункту "Cherries" також би виконалися.

+ +
switch (fruittype) {
+  case 'Oranges':
+    console.log('Oranges are $0.59 a pound.');
+    break;
+  case 'Apples':
+    console.log('Apples are $0.32 a pound.');
+    break;
+  case 'Bananas':
+    console.log('Bananas are $0.48 a pound.');
+    break;
+  case 'Cherries':
+    console.log('Cherries are $3.00 a pound.');
+    break;
+  case 'Mangoes':
+    console.log('Mangoes are $0.56 a pound.');
+    break;
+  case 'Papayas':
+    console.log('Mangoes and papayas are $2.79 a pound.');
+    break;
+  default:
+   console.log('Sorry, we are out of ' + fruittype + '.');
+}
+console.log("Is there anything else you'd like?");
+ +

Інструкції для обробки винятків

+ +

Використовуючи інструкцію throw , можна викидати виключення і обробляти їх за допомогою інструкцій try...catch.

+ + + +

Типи винятків

+ +

В якості виключення у JavaScript можна викинути практично будь-який об'єкт. Тим не менш, не всі викинуті об'єкти створено однаковими. Позаяк доволі звичною практикою є викидати числа чи стрічки в якості помилок, часто краще використовувати якийсь із типів винятків, спеціально створених для цих потреб:

+ + + +

Оператор throw

+ +

Скористайтеся оператором throw, щоб викинути виняток. Коли викидаєте виняток, ви вказуєте вираз, що містить значення, яке викидається:

+ +
throw expression;
+
+ +

Ви можете викинути будь-який вираз, не тільки вирази окремих типів. Наступний код викидає кілька винятків різних типів:

+ +
throw 'Error2';   // тип String
+throw 42;         // тип Number
+throw true;       // тип Boolean
+throw {toString: function() { return "Я об'єкт!"; } };
+
+ +
Примітка: Ви можете вказати об'єкт, коли викидаєте виняток. Після цього ви можете звертатися до властивостей об'єкта у блоці catch.
+ +
// Створити об'єкт UserException
+function UserException(message) {
+  this.message = message;
+  this.name = 'UserException';
+}
+
+// Гарненько оформити виняток у разі використання в якості рядка
+// (наприклад, у консолі помилок)
+UserException.prototype.toString = function() {
+  return this.name + ': "' + this.message + '"';
+}
+
+// Створити екземпляр об'єкта та викинути його
+throw new UserException('Значення завелике');
+ +

Інструкція try...catch

+ +

Інструкція try...catch позначає блок інструкцій, які програма спробує виконати, і вказує одну чи більше реакцій на викинутий виняток. Коли викидається виняток, інструкція try...catch його ловить.

+ +

Інструкція try...catch складається з блока try, що містить одну чи більше інструкцій, і блоку catch, що містить інструкції до виконання у разі, якщо у блоці try буде викинуто виняток.

+ +

Інакше кажучи, ми хочемо, щоб блок try успішно виконався. Але якщо так не станеться, ми хочемо, щоб управління перейшло до блоку catch. Практично, якщо будь-яка з інструкцій всередині блоку try (або всередині функції, викликаної зсередини блоку try) викидає виняток, управління одразу передається до блоку catch. У разі, якщо блок try не викинув жодного винятку, блок catch пропускається. А блок finally виконується після виконання try та catch і до інструкцій, що слідують після Інструкції try...catch.

+ +

Наступний приклад містить інструкцію try...catch. У прикладі викликається функція, що повертає назву місяця з масиву, керуючись номером, переданим у функцію. Якщо число не відповідає номерові місяця (112), викидається виняток зі стрічкою "InvalidMonthNo" в якості значення, а інструкції, описані у блоці catch, встановлюють значення змінної monthName у 'unknown'.

+ +
function getMonthName(mo) {
+  mo = mo - 1; // Коригуємо порядковий номер місяця для використання в якості
+               // індекса масиву (1 = Jan, 12 = Dec)
+  var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul',
+                'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
+  if (months[mo]) {
+    return months[mo];
+  } else {
+    throw 'InvalidMonthNo'; // тут застосуємо ключове слово throw
+  }
+}
+
+try { // інструкції, які ми намагаємося виконати
+  monthName = getMonthName(myMonth); // функція може викинути виняток
+}
+catch (e) {
+  monthName = 'unknown';
+  logMyErrors(e); // передаємо значення винятку в обробник помилок (наприклад, вашу власну функцію)
+}
+
+ +

Блок catch

+ +

Блок catch можна використовувати для обробки всіх винятків, що можуть виникнути при виконання блоку try.

+ +
catch (catchID) {
+  інструкції
+}
+ +

Блок catch задає ідентифікатор (catchID у прикладі вище), що містить значення, вказане оператором throw. За допомогою цього ідентифікатора можна отримати інформацію про виняток, який було викинуто.

+ +

JavaScript створює цей ідентифікатор, як тільки управління переходить до блоку catch. Ідентифікатор існує доти, доки виконується catch. Як тільки блок catch завершує роботу, ідентифікатор знищується.

+ +

Наприклад, наступний код викидає виняток. Коли це відбувається, управління передається до блоку catch.

+ +
try {
+  throw 'myException'; // створює виняток
+}
+catch (e) {
+  // інструкції для обробки якихось винятків
+  logMyErrors(e); // передає об'єкт винятку до обробника помилок
+}
+
+ +
+

Найкращі практики: Під час запису помилок до консолі всередині блоку catch для потреб зневадження рекомендується використовувати console.error() замість console.log(). Це одразу форматує повідомлення як помилку, і також додає його до загального списку помилок, що трапилися на сторінці. 

+
+ +

Блок finally

+ +

Блок finally містить інструкції для виконання після завершення роботи блоку try...catch. Блок finally також виконається перед кодом, що слідує безпосередньо за оператором try…catch…finally.

+ +

Також важливо зауважити, що блок finally буде виконано незалежно від того, чи було викинуто виняток. Однак, якщо виняток таки було викинуто, інструкції блоку finally буде виконано, навіть якщо жоден блок catch не обробив викинутий виняток.

+ +

Блок finally можна використовувати, щоб заставити скрипт "м'яко впасти", коли трапляється виняток. Наприклад - для того, щоб звільнити ресурс, взятий скриптом.

+ +

Приклад, наведений далі, відкриває файл і виконує певні дії з ним. (JavaScript на сервері дозволяє отримувати доступ до файлів.) Якщо викидається виняток, поки файл було відкрито, блок finally закриває файл перед тим, як скрипт впаде. Застосування finally тут гарантує, що файл ні в якому разі не залишиться відкритим, навіть якщо трапиться помилка.

+ +
openMyFile();
+try {
+  writeMyFile(theData); // Це може викинути помилку
+} catch(e) {
+  handleError(e); // Обробити помилку, якщо вона трапиться
+} finally {
+  closeMyFile(); // Завжди закривати ресурс
+}
+
+ +

Якщо блок finally повертає якесь значення, це значення стає результатом роботи всього блоку try-catch-finally, незалежно від будь-яких інструкцій return всередині try чи catch:

+ +
function f() {
+  try {
+    console.log(0);
+    throw 'bogus';
+  } catch(e) {
+    console.log(1);
+    return true; // ця інструкція чекатиме
+                 // допоки не виконається блок finally
+    console.log(2); // недосяжний код
+ } finally {
+    console.log(3);
+    return false; // переписує попередній "return"
+    console.log(4); // недосяжний код
+  }
+  // тепер виконується "return false"
+  console.log(5); // недосяжний код
+}
+f(); // console 0, 1, 3; returns false
+
+ +

Переписування значень "return" блоком finally також стосується винятків, викинутих (можливо, повторно) всередині блоку catch :

+ +
function f() {
+  try {
+    throw 'bogus';
+  } catch(e) {
+    console.log('упіймано внутрішній "bogus"');
+    throw e; // ця інструкція чекатиме,
+             // допоки не виконається бльок finally
+  } finally {
+    return false; // переписує попередній "throw"
+  }
+  // тепер виконується "return false"
+}
+
+try {
+  f();
+} catch(e) {
+  // цей код ніколи не виконається, бо "throw"
+  // усередині "catch" переписано
+  // "return"ом у "finally"
+  console.log('упіймано зовнішній "bogus"');
+}
+
+// ВИВІД:
+// упіймано внутрішній "bogus"
+ +

Вкладені інструкції try...catch

+ +

Можна вкладати одну чи більше інструкцій try...catch. Якщо внутрішня інструкція try...catch не має блоку catch, мусить бути блок finally, і блок catch зовнішної інструкції try...catch буде перевірено на збіг. За детальнішою інфорацією див. nested try-blocks на сторінці try...catch.

+ +

Обробка об'єктів Error

+ +

Залежно від типу помилки, ви зможете використати властивості 'name' і 'message' для покращеного повідомлення. 'name' переважно називає клас, похідний від класу Error (напр., 'DOMException' або 'Error'), а 'message' традиційно дає стисліше повідомлення, ніж те, що виходить після конвертування об'єкта помилки у string.

+ +

Якщо ви викидаєте влавні винятки, то для користі з цих властивостей (напр., щоб ваш блок catch відрізняв ваші винятки від системних) сожете скористатися конструктором Error. Наприклад:

+ +
function doSomethingErrorProne() {
+  if (ourCodeMakesAMistake()) {
+    throw (new Error('Повідомлення'));
+  } else {
+    doSomethingToGetAJavascriptError();
+  }
+}
+....
+try {
+  doSomethingErrorProne();
+} catch (e) {
+  console.log(e.name); // logs 'Error'
+  console.log(e.message); // logs 'Повідомлення' або JavaScript error message)
+}
+ +

Обіцянки (Promises)

+ +

Починаючи з ECMAScript2015, JavaScript дістав підтримку об'єктів {{jsxref("Promise")}}, що дає змогу контролювати плин відкладених і асинхронних операцій.

+ +

Обіцянка (Promise) має один зі станів:

+ + + +

+ +

Завантаження образу з допомогою XHR

+ +

Простий приклад використання Обіцянки (Promise) і XMLHttpRequest для завантаження образу міститься в репозиторії MDN GitHub js-examples repository. Ви також можете бачити її в дії: see it in action. Кожен крок прокоментовано, що дає змогу зблизька побачити архітектуру Обіцянок (Promises) і XHR. Тут наведено розкоментовану версію, що показує плин Обіцянки (Promise) , тож ви можете схопити ідею:

+ +
function imgLoad(url) {
+  return new Promise(function(resolve, reject) {
+    var request = new XMLHttpRequest();
+    request.open('GET', url);
+    request.responseType = 'blob';
+    request.onload = function() {
+      if (request.status === 200) {
+        resolve(request.response);
+      } else {
+        reject(Error('Image didn\'t load successfully; error code:'
+                     + request.statusText));
+      }
+    };
+    request.onerror = function() {
+      reject(Error('There was a network error.'));
+    };
+    request.send();
+  });
+}
+ +

За деталями звертайтеся до сторінки {{jsxref("Promise")}} і посібника Using Promises.

+ +
{{PreviousNext("Web/JavaScript/Guide/Grammar_and_types", "Web/JavaScript/Guide/Loops_and_iteration")}}
diff --git a/files/uk/web/javascript/guide/dokladno_pro_objectnu_model/index.html b/files/uk/web/javascript/guide/dokladno_pro_objectnu_model/index.html new file mode 100644 index 0000000000..5e756710dd --- /dev/null +++ b/files/uk/web/javascript/guide/dokladno_pro_objectnu_model/index.html @@ -0,0 +1,760 @@ +--- +title: Докладно про об'єктну модель +slug: Web/JavaScript/Guide/Dokladno_pro_Objectnu_Model +tags: + - Guide + - Intermediate + - JavaScript + - Object +translation_of: Web/JavaScript/Guide/Details_of_the_Object_Model +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Using_promises")}}
+ +

JavaScript - це об'єктна мова, що заснована на прототипах, а не на класах. У зв'язку з цим може бути менш очевидно, як саме JavaScript  дозволяє створювати ієрархії об'єктів із наслідуванням їх властивостей та значень. Цей розділ є спробою дещо прояснити цей механізм.

+ +

Вміст цього розділу розрахований на те, що ви вже, принаймні, дещо знайомі з мовою JavaScript, і застосовували його функції для створення простих об'єктів.

+ +

Мови з класовою та прототипною моделлю

+ +

Об'єктно-орієнтовані мови з класовою моделлю, такі як Java і C++, засновані на концепції двох окремих сутностей: класів та екземплярів.

+ + + +

Мови з прототипною моделлю наслідування, такі як JavaScript, не розділяють ці сутності: у них просто є об'єкти. Такі мови реалізовують поняття об'єкту-прототипу — об'єкту, що використовується як зразок, з якого вибираються початкові властивості для нового об'єкту. Будь-який об'єкт може вказати власні властивості, як в момент створення, так і під час виконання. Ну і на додачу, будь-який об'єкт можна задати в якості прототипу з іншого об'єкту — таким чином перший об'єкт розділить свої властивості з другим.

+ +

Задання і визначення класу

+ +

У мовах із класовою моделлю, класс задається у окремому визначенні класу. У цому визначенні можна вказати особливі методи, що називаються конструкторами, щоб створити екземпляри класу. Метод-конструктор може задати початкові значення властивостей екземпляру, і виконати якісь інші задачі прямо у момент створення. Для створення екземплярів застосовується оператор new у комбінації із методом-конструктором.

+ +

JavaScript слідує подібній моделі, проте не має відокремленого від конструктора визначення класу. Натомість, ви одразу задаєте функцію-конструктор, щоб створити об'єкти із відповідним початковим набором властивостей та значень. Будь-яка JavaScript-функція може використовуватись як конструктор. Для створення нового об'єкту так само використовується оператор new із фукнцією-конструктором.

+ +

 

+ +
+

Зауважте, що ECMAScript 2015 вводить визначення класу:

+ +
+

Класи JavaScript, введені стандартом ECMAScript 2015, є лише синтаксичним цукром поверх уже наявного у JavaScript прототипного наслідування. Тобто ці класи не вводять у JavaScript нової моделі наслідуваня.

+
+
+ +

 

+ +

Дочірні класи і наслідування

+ +

У мові з класовою моделлю наслідкування ієрархія класів створюється через визначення класу. У цьому визначенні можна окремо вказати, що новий клас являється дочірнім стосовно уже наявного класу. Дочірній клас отримає всі властивості батьківського і може привнести нові (або ж змінити успадковані). Наприклад, припустимо, що клас Employee включає в себе лише поля name та dept, і Manager - це дочірній клас Employee, що додає властивість reports. У цьому випадку, екземпляр класу Manager матиме три властивості: name, dept, та reports.

+ +

JavaScript реалізовує наслідування дещо інакше. Він дозволяє пов'язувати об'єкт-прототип із будь-якою фукнцією-конструктором. Тобто ви можете точнісінько реалізувати приклад EmployeeManager, проте використовуючи дещо інші терміни. Спершу ви визначаєте конструктор Employee, задаючи властивості name та dept. Далі ви визначаєте фукнцію-конструктор Manager, що викликає конструктор Employee та задає властивість reports. Насамкінець, призначаєте новий об'єкт, отриманий з Employee.prototype в якості прототипу конструктора Manager. Надалі, при створенні екземпляра Manager він наслідує властивості name і dept з об'єкту Employee.

+ +

Додавання і видалення властивостей

+ +

Зазвичай у мовах із класовою моделлю наслідування класи створюються під час компіляції, а екземпляри класів - під час компіляції чи виконання програми. Після того, як його було визначено, не можна змінити кількість або тип його властивостей. Однак, у JavaScript можна додавати чи видаляти властивості будь-якого об'єкту безпосередньо під час виконання програми. Якщо додати нову властивість до об'єкту-прототипу певного набору об'єктів, вони всі також отримають цю властивість.

+ +

Підсумок відмінностей класової і прототипної моделей

+ +

Наступна таблиця надає короткий підсумок цих відмінностей. Решта розділу розкриває деталі застосування JavaScript-конструкторів і прототипів для створення ієрархії об'єктів, та порівнює це із тим, як би це робилось у Java.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Порівняння мови із класовою моделлю наслідування (Java) і прототипною (JavaScript)
Класова модель (Java)Прототипна модель (JavaScript)
Клас та його екземпляр - окремі сутності.Всі об'єкти можуть наслідувати інші об'єкти.
Визначення класу описує його; екземпляри створюються методами-конструкторами.Функції-конструктори і описують, і створюють набори об'єктів.
Окремий об'єкт створюється оператором new.Так само.
Ієрархія об'єктів формується при визначенні класів, шляхом задання нащадків для уже наявних класів.Ієрархія об'єктів формується шляхом призначення об'єкту прототипом функції-конструктора.
Властивості наслідуються згідно ланцюжка класів.Властивості наслідуються згідно ланцюжка прототипів.
Визначення класу задає всі властивості всіх екземплярів класу. Неможливо динамічно додавати властивості під час виконання програми.Функція-конструктор чи прототип задають лише початковий набір властивостей. Можна додавати чи видаляти властивості як окремого об'єкту, так певного їх набору.
+ +

Приклад із робітником "Employee"

+ +

Надалі у розділі ієрархія робітників, що показана на наступному зображенні.

+ +
+
+

Проста ієрархія об'єктів, сформована із наступних елементів:

+ +

+
+ +
+
    +
  • Employee має поля name (із порожнім рядком в якості значення за замовчуванням) та dept (у якого значення за замовчуванням — "general").
  • +
  • Manager заснований на Employee. Він додає властивість reports  (за замовчуванням містить порожній масив для об'єктів Employee).
  • +
  • WorkerBee також заснований на Employee. Він додає властивість projects (за замовчуванням містить порожній масив, призначений для рядків).
  • +
  • SalesPerson заснований на WorkerBee. Він додає властивість quota (за замовчуванням — число 100). Він також перевизначае властивість dept, надаючи їй нове значенням "sales" (що означає, що всі SalesPerson відносяться до одного відділу).
  • +
  • Engineer заснований на WorkerBee. Він додає властивість machine (значення за замовчуванням — порожній рядок) і перевизначає властивість dept, задаючи їй значення "engineering".
  • +
+
+
+ +

Створення ієрархії

+ +

Існує декілька способів задати відповідні функції-конструктори, щоб реалізувати ієрархію робітників. Який спосіб обрати — значною мірою залежить від того, які можливості ви хочете отримати від вашого додатку.

+ +

Цей розділ показує, як використовувати дуже прості (і відносно негнучкі) визначення, і таким чином демонструє, як отримати робочий механізм наслідування. У цих визначеннях не можна задати жодного значення при створенні об'єкту — він отримає властивості із значеннями за замовчуванням, які можна буде змінити пізніше.

+ +

У реальному додатку ви б, ймовірно, визначали конструктор, що дозволяє задавати значення в момент створення об'єкту (докладніше у Більш гнучкі конструктори). А наразі ці прості визначення покажуть, як загалом відбувається наслідування.

+ +

Наступні визначення Employee у Java та JavaScript ідентичні. Єдина відмінність — у Java необхідно явно вказувати тип кожної властивості, на відміну від JavaScript (так як Java — мова із сильною типізацією, а JavaScript — із слабкою).

+ +
+

JavaScript

+ +
function Employee() {
+  this.name = '';
+  this.dept = 'general';
+}
+
+ +


+ Java

+ +
public class Employee {
+   public String name = "";
+   public String dept = "general";
+}
+
+
+ +

Визначення Manager і WorkerBee показують різницю у заданні батьківського об'єкту. У JavaScript ви додаєте екземпляр прототипу в якості значення поля prototype функції-конструктора, а потім перевизначаєте prototype.constructor, щоб це поле вказувало на функцію-конструктор. Ви можете це зробити в будь-якому місці після визначення конструктора. У Java надклас задається всередині визначення класу, і його ніяк не можна змінити зовні визначення класу.

+ +
+

JavaScript

+ +
function Manager() {
+  Employee.call(this);
+  this.reports = [];
+}
+Manager.prototype =
+    Object.create(Employee.prototype);
+Manager.prototype.constructor = Manager;
+
+function WorkerBee() {
+  Employee.call(this);
+  this.projects = [];
+}
+WorkerBee.prototype =
+    Object.create(Employee.prototype);
+WorkerBee.prototype.constructor = WorkerBee;
+
+ +


+ Java

+ +
public class Manager extends Employee {
+   public Employee[] reports =
+       new Employee[0];
+}
+
+
+
+public class WorkerBee extends Employee {
+   public String[] projects = new String[0];
+}
+
+
+
+
+ +

 

+ +

Визначення Engineer та SalesPerson створюють об'єкти, що наслідуються вже від WorkerBee, а, отже, і від Employee. Об'єкти цих типів мають властивості всіх об'єктів вище у ланцюжку наслідування. Надодачу, ці визначення перевизначають успадковані значення поля dept, змінюючи їх відповідно до нового типу.

+ +
+

JavaScript

+ +
function SalesPerson() {
+   WorkerBee.call(this);
+   this.dept = 'sales';
+   this.quota = 100;
+}
+SalesPerson.prototype =
+    Object.create(WorkerBee.prototype);
+SalesPerson.prototype.constructor = SalesPerson;
+
+function Engineer() {
+   WorkerBee.call(this);
+   this.dept = 'engineering';
+   this.machine = '';
+}
+Engineer.prototype =
+    Object.create(WorkerBee.prototype);
+Engineer.prototype.constructor = Engineer;
+
+ +


+ Java

+ +
public class SalesPerson extends WorkerBee {
+   public String dept = "sales";
+   public double quota = 100.0;
+}
+
+
+public class Engineer extends WorkerBee {
+   public String dept = "engineering";
+   public String machine = "";
+}
+
+
+
+ +

Таким чином, ви можете створювати екземпляри об'єктів із уже заданими значеннями для своїх властивостей. Наступна схема ілюструє застосування цих JavaScript-визначень для створення нових об'єктів, і демонструє значення їх властивостей.

+ +
+

Зауважте, що: термін екземпляр має специфічний технічний зміст у мовах із класовою моделлю. У цих мовах екземпляр являється окремою реалізацією класу і корінним чином відрізняється від його визначення. У JavaScript, "екземпляр" не має такого особливого змісту, бо сам JavaScript не має такої значної відмінності класів від їх реалізацій. Однак, у контексті JavaScript, "екземпляр" може неформально позначати об'єкт, створений певною функцією-конструктором. Тому, згідно наступного прикладу, можна неформально стверджувати, що jane є екземпляром класу Engineer. Так само, хоча терміни предок, нащадок, дочірній і батьківський класи не мають формального смісту в JavaScript, їх можна застосовувати для позначення об'єктів, що знаходяться вище чи нижче у ланцюжку прототипів.

+
+ +

Створення об'єктів за допомогою простих визначень

+ +
+

Ієрархія об'єктів

+ +

Наступна ієрархія створена за допомогою коду у правій частині.

+ +

+ +

Окремі об'єкти = Jim, Sally, Mark, Fred, Jane, etc.
+ "Екземпляри", створені конструктором

+ +
var jim = new Employee;
+// Дужки можна опустити, якщо
+// конструктор не приймає аргументів.
+// jim.name має значення ''
+// jim.dept має значення 'general'
+
+var sally = new Manager;
+// sally.name має значення ''
+// sally.dept має значення 'general'
+// sally.reports має значення []
+
+var mark = new WorkerBee;
+// mark.name має значення ''
+// mark.dept має значення 'general'
+// mark.projects має значення []
+
+var fred = new SalesPerson;
+// fred.name має значення ''
+// fred.dept має значення 'sales'
+// fred.projects має значення []
+// fred.quota має значення 100
+
+var jane = new Engineer;
+// jane.name має значення ''
+// jane.dept має значення 'engineering'
+// jane.projects має значення []
+// jane.machine має значення ''
+
+
+ +

Властивості (поля) об'єкту

+ +

Ця секція описує, як об'єкти наслідують властивості інших об'єктів у ланцюжку прототипів, і що відбувається, якщо додати властивість під час виконання програми.

+ +

Наслідування властивостей

+ +

Припустимо, такою інструкцією ви створили екземпляр WorkerBee — об'єкт mark:

+ +
var mark = new WorkerBee;
+
+ +

Коли JavaScript бачить оператор new, він створює загальний об'єкт і неявно встановлює WorkerBee.prototype значенням внутрішньої властивості [[Prototype]], і передає цей новий об'єкт як значення this до фукнції-конструктора WorkerBee. Внутрішня властивість [[Prototype]] визначає ланцюжок прототипів для виводу значень полів. Коли ці властивості задані, JavaScript повертає новий об'єкт, а інструкція присвоєння задає його в якості значення змінної mark.

+ +

Описаний процес явно не встановлює значення об'єкту mark для властивостей (локальні значення), які mark наслідує з ланцюжка прототипів. Коли ви запитуєте значення властивості, JavaScript в першу чергу перевіряє наявність цього значення у об'єкті, і повертає його, якщо знаходить. Якщо ж ні, JavaScript перевіряє весь ланцюжок прототипів (за допомогою властивості [[Prototype]]). Якщо об'єкт у ланцюжку має таку властивість - буде повернуто її значення (або повідомлення, що об'єкт не має такої властивості, якщо її все-таки не було знайдено). Таким чином, об'єкт mark має наступні властивості і значення:

+ +
mark.name = '';
+mark.dept = 'general';
+mark.projects = [];
+
+ +

З конструктора Employee об'єкту mark призначено локальні значення для властивостей name та dept, а з конструктора WorkerBee — значення властивості projects. Таким чином ми отримуємо наслідування властивостей і їх значень у JavaScript. Деякі тонкощі цього процесу додатково висвітлені у Іще раз про наслідування властивостей.

+ +

Так як ці конструктори не дозволяють задати специфічні для екземпляру значення, це являється загальним прикладом. В якості значень властивостей взяті значення за замовчуванням, що розповсюджуються на всі об'єкти, створені на основі WorkerBee. Звісно, значення цих властивостей можна змінити. Наприклад, так можна встановити їх значення для об'єкту mark:

+ +
mark.name = 'Doe, Mark';
+mark.dept = 'admin';
+mark.projects = ['navigator'];
+ +

Додавання властивостей

+ +

У JavaScript, можна додавати властивості до об'єкту безпосередно під час виконання. Ви не обмежені застосуванням лише властивостей, наданих конструктором. Щоб додати нову властивість до окремого об'єкту, просто призначте йому нове значення, як наведено далі:

+ +
mark.bonus = 3000;
+
+ +

Тепер об'єкт mark містить властивість bonus, проте більше ніхто із WorkerBee її не має.

+ +

Якщо додати нову властивість до об'єкту-прототипу іншого конструктора, то ця властивість з'явиться у всіх об'єктів, що наслідують властивості від прототипу. Наприклад, ось так можна додати властивість specialty всім робітникам:

+ +
Employee.prototype.specialty = 'none';
+
+ +

Як тільки JavaScript виконає інструкцію, об'єкт mark матиме властивість specialty із значенням "none". Наступна схема ілюструє ефект від додавання цієї властивості до прототипу Employee і її перевизначення у прототипі Engineer.

+ +


+ Додавання властивостей

+ +

Більш гнучкі конструктори

+ +

Наведені раніше функції-конструктори не дозволяють задавати значення під час створенні екземпляру. Як і у Java, можна надати конструктору аргументи для ініціалізації значень властивостей у об'єктів. Наступна схема показує один із способів це зробити.

+ +


+ Задання властивостей у конструкторі, варіант 1

+ +

Таблиця далі показує визначення цих об'єктів у Java і JavaScript.

+ +
+

JavaScript

+ +

Java

+
+ +
+
function Employee(name, dept) {
+  this.name = name || '';
+  this.dept = dept || 'general';
+}
+
+ +

 

+ +

 

+ +

 

+ +

 

+ +

 

+ +
public class Employee {
+   public String name;
+   public String dept;
+   public Employee () {
+      this("", "general");
+   }
+   public Employee (String name) {
+      this(name, "general");
+   }
+   public Employee (String name, String dept) {
+      this.name = name;
+      this.dept = dept;
+   }
+}
+
+
+ +
+
function WorkerBee(projs) {
+
+ this.projects = projs || [];
+}
+WorkerBee.prototype = new Employee;
+
+ +

 

+ +

 

+ +

 

+ +
public class WorkerBee extends Employee {
+   public String[] projects;
+   public WorkerBee () {
+      this(new String[0]);
+   }
+   public WorkerBee (String[] projs) {
+      projects = projs;
+   }
+}
+
+
+ +
+
+function Engineer(mach) {
+   this.dept = 'engineering';
+   this.machine = mach || '';
+}
+Engineer.prototype = new WorkerBee;
+
+ +

 

+ +

 

+ +

 

+ +
public class Engineer extends WorkerBee {
+   public String machine;
+   public Engineer () {
+      dept = "engineering";
+      machine = "";
+   }
+   public Engineer (String mach) {
+      dept = "engineering";
+      machine = mach;
+   }
+}
+
+
+ +

Ці JavaScript-визначення застосовують особливу ідіому для задання значення за замовчуванням:

+ +
this.name = name || '';
+
+ +

Логічний оператор АБО у JavaScript (||) обчислює перше значення. Якщо результат можна привести до true, оператор повертає його, а інакше - значення другого аргументу. Таким чином, ця стрічка коду перевіряє, чи name має якесь корисне значення для властивості name. Якщо так — this.name отримує її значення, а інакше значенням this.name стає порожній рядок. У розділі ця ідіома застосовується для стислості; однак вона може бути неочевидною на перший погляд.

+ +
+

Зауважте, що: це може працювати не так, як очікується, якщо конструктор викликається із аргументами, що приводяться до false (число 0 і порожній рядок (""). У цьому випадку буде обрано значення за замовчуванням.

+
+ +

Таким чином можливо задати значення для властивостей на місці, безпосередньо під час створення екземпляру об'єкту. Наступною інструкцією ви можете створити новий екземпляр Engineer:

+ +
var jane = new Engineer('belau');
+
+ +

Властивості Jane тепер виглядають так:

+ +
jane.name == '';
+jane.dept == 'engineering';
+jane.projects == [];
+jane.machine == 'belau';
+
+ +

Зауважте, що таким визначенням ви не можете задати первинне значення для наслідуваного поля name. Для задання значення наслідуваним властивостям у JavaScript, необхідно додати трохи більше коду до фукнції-конструктора.

+ +

Поки що фукнція-конструктор створила загальний об'єкт, задала на місці властивості і значення нового об'єкту. Можна зробити, щоб конструктор додавав властивості безпосередньо викликаючи конструктор об'єкта, вищого у ієрархії прототипів. Власне, як зображено у наступній схемі.

+ +


+ Задання властивостей у конструкторі, варіант 2

+ +

Розгляньмо детальніше одне із цих визначень. Ось новий конструктор Engineer:

+ +
function Engineer(name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, 'engineering', projs);
+  this.machine = mach || '';
+}
+
+ +

Припустимо, ви ось так створюєте новий об'єкт Engineer:

+ +
var jane = new Engineer('Doe, Jane', ['navigator', 'javascript'], 'belau');
+
+ +

Тут JavaScript виконує наступні кроки:

+ +
    +
  1. Оператор new створює загальний об'єкт і задає Engineer.prototype значенням його властивості __proto__ .
  2. +
  3. Оператор new передає новий об'єкт у конструктор Engineer в якості значення this.
  4. +
  5. Конструктор створює нову властивість base для цього об'єкту і присвоює їй значення конструктора WorkerBee. Так конструктор WorkerBee стає методом об'єкту Engineer. Назва властивості base не є чимось особливим. Ви можете використати будь-яке дозволене ім'я властивості, а base просто звучить змістовно для даного випадку.
  6. +
  7. Конструктор викликає метод base, передаючи в нього два своїх аргументи ("Doe, Jane" і ["navigator", "javascript"]) і новий рядок "engineering". Явно вказаний "engineering" у конструкторі означає, що всі об'єкти Engineer матимуть одне значення для наслідуваної властивості dept, і це значення заміщує успадковане від Employee.
  8. +
  9. Так як метод base належить Engineer, всередині виклику base JavaScript прив'язує значення this до об'єкту, створеного на першому етапі. Таким чином функція WorkerBee, в свою чергу, передає аргументи "Doe, Jane" та "engineering" до конструктора Employee. Після повернення з конструктора Employee функція WorkerBee задає останнім аргументом поле projects.
  10. +
  11. Після повернення з методу base конструктор Engineer ініціалізовує властивість machine об'єкту значенням "belau".
  12. +
  13. Після повернення з конструктору JavaScript присвоює новий об'єкт змінній jane.
  14. +
+ +

Може скластися враження, що, викликавши конструтктор WorkerBee зсередини конструктора Engineer, ви вкажете наслідування відповідно для об'єктів Engineer. Насправді виклик конструктора WorkerBee гарантує, що об'єкт Engineer матиме всі властивості, вказані у всіх викликаних конструкторах. Однак, якщо пізніше додати нові властивості до прототипів Employee чи WorkerBee, вони не будуть успадковані об'єктом Engineer. Припустимо, у нас є наступні інструкції:

+ +
function Engineer(name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, 'engineering', projs);
+  this.machine = mach || '';
+}
+var jane = new Engineer('Doe, Jane', ['navigator', 'javascript'], 'belau');
+Employee.prototype.specialty = 'none';
+
+ +

Об'єкт jane не наслідує властивість specialty. Вам все ще необхідно явно вказувати прототип для гарантії динамічного наслідування. Натомість розглянемо такий набір інструкцій:

+ +
function Engineer(name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, 'engineering', projs);
+  this.machine = mach || '';
+}
+Engineer.prototype = new WorkerBee;
+var jane = new Engineer('Doe, Jane', ['navigator', 'javascript'], 'belau');
+Employee.prototype.specialty = 'none';
+
+ +

Тепер значенням властивості specialty об'єкту jane являється "none".

+ +

Іншим способом наслідування являється використання методів call() чи apply(). Ось дві еквівалентні ділянки коду:

+ +
+
function Engineer(name, projs, mach) {
+  this.base = WorkerBee;
+  this.base(name, 'engineering', projs);
+  this.machine = mach || '';
+}
+
+ +
function Engineer(name, projs, mach) {
+  WorkerBee.call(this, name, 'engineering', projs);
+  this.machine = mach || '';
+}
+
+
+ +

Використання методу call() дає більш чисту реалізацію, так як base більше не потрібен.

+ +

Іще раз про наслідування властивостей

+ +

У попередніх частинах було описано, як конструктори і прототипи JavaScript дозволяють реалізовувати ієрархію та наслідування. Ця частина розглядає деякі тонкощі, які, можливо, не були очевидними у наведеному вище тексті.

+ +

Локальні і успадковані змінні

+ +

Коли ви викликаєте властивість, JavaScript виконує наступні кроки (як описано вище у главі):

+ +
    +
  1. Перевіряє наявність цієї змінної прямо в об'єкті, і повертає її значення, якщо знаходить.
  2. +
  3. Якщо її немає серед локальних змінних - перевіряє ланцюжок прототипів (використовуючи властивість __proto__).
  4. +
  5. Якщо прототип у ланцюжку має значення вказаної властивості — повертає це значення.
  6. +
  7. Якщо вказана властивість не знайдена — значить, об'єкт її не має.
  8. +
+ +

Результат виконання цих кроків залежить від того, як ви задаєте значення і об'єкти.  Перший приклад мав такі визначення:

+ +
function Employee() {
+  this.name = '';
+  this.dept = 'general';
+}
+
+function WorkerBee() {
+  this.projects = [];
+}
+WorkerBee.prototype = new Employee;
+
+ +

Припустимо, враховуючи ці визначення, що наступною інструкцією ви створили екземпляр WorkerBee у змінній amy:

+ +
var amy = new WorkerBee;
+
+ +

Об'єкт amy має одну локальну змінну — projects. Значення властивостей name та dept насправді не належать amy, і тому виводяться через поле її поле __proto__. Отже, amy має такі значення властивостей:

+ +
amy.name == '';
+amy.dept == 'general';
+amy.projects == [];
+
+ +

Тепер припустимо, що ви змінили значення властивості name у прототипі, асоційованому з Employee:

+ +
Employee.prototype.name = 'Unknown';
+
+ +

На перший погляд, можна очікувати, що нове значення пошириться на всі екземпляри Employee. Однак, це не так.

+ +

При створенні будь-якого екземпляру об'єкту Employee, цей екземпляр отримає локальне значення для властивості name (порожній рядок). Тобто, коли ми задаємо прототип WorkerBee шляхом створення нового об'єкту Employee, WorkerBee.prototype має локальне значення властивості name. Отже, коли JavaScript шукає властивість name об'єкту amy (екземпляр WorkerBee), він знаходить місцеве значення властивості у WorkerBee.prototype. І тому він не намагається шукати далі в ланцюжку прототипів до Employee.prototype.

+ +

Якщо ви хочете змінити значення властивості під час виконання, та ще й так, щоб воно поширилось на всіх нащадків  об'єкту, слід визначати це значення не у конструкторі об'єкту, а у прототипі конструктора. Припустимо, наприклад, що ви змінили попередній варіант реалізації на такий:

+ +
function Employee() {
+  this.dept = 'general';    // Зауважте, що тут немає this.name (локальної змінної)
+}
+Employee.prototype.name = '';    // Одна копія
+
+function WorkerBee() {
+  this.projects = [];
+}
+WorkerBee.prototype = new Employee;
+
+var amy = new WorkerBee;
+
+Employee.prototype.name = 'Unknown';
+
+ +

У цьому випадку, властивість amy name стане "Unknown".

+ +

Як ілюструють ці приклади, якщо вам потрібно і мати значення за замовчуванням для властивостей об'єктів, і можливість змінювати ці значення за замовчуванням під час виконання, слід задавати властивості у прототипі конструктора, а не у самому конструкторі.

+ +

Визначення відносин екземпляру

+ +

Пошук властивості у JavaScript виконується серед власних властивостей об'єкту, і, якщо властивість з даним іменем не була знайдена, пошук переходить всередину особливої властивості __proto__. Це відбувається рекурсивно, і цей процес називається "пошук у ланцюжку прототипів".

+ +

Властивість __proto__ встановлюється у момент конструювання об'єкту; вказує вона на властивість prototype конструктора. Тобто вираз new Foo() створює об'єкт із__proto__ == Foo.prototype. Відповідно, зміни у Foo.prototype впливають на пошук властивості всіх об'єктів, створених через new Foo().

+ +

Кожен об'єкт має властивість __proto__ (за винятком Object); кожна функція має властивість prototype. Тобто об'єкти можуть відноситись один до одного згідно "прототипного наслідування". Перевірити наслідування можна, порівнюючи властивість __proto__ об'єкту із об'єктом prototype функції. JavaScript надає скорочення: оператор instanceof порівнює об'єкт і функцію, і повертає true, якщо об'єкт є нащадком прототипу функції. Наприклад:

+ +
var f = new Foo();
+var isTrue = (f instanceof Foo);
+ +

Для більш докладного прикладу, припустимо, що у нас є набір визначень із показаних у Наслідування властивостей. Створімо об'єкт Engineer:

+ +
var chris = new Engineer('Pigman, Chris', ['jsd'], 'fiji');
+
+ +

Наступні вирази стосовно цього об'єкту являються істинними:

+ +
chris.__proto__ == Engineer.prototype;
+chris.__proto__.__proto__ == WorkerBee.prototype;
+chris.__proto__.__proto__.__proto__ == Employee.prototype;
+chris.__proto__.__proto__.__proto__.__proto__ == Object.prototype;
+chris.__proto__.__proto__.__proto__.__proto__.__proto__ == null;
+
+ +

Враховуючи це, ми можемо ось так написати функцію instanceOf:

+ +
function instanceOf(object, constructor) {
+   object = object.__proto__;
+   while (object != null) {
+      if (object == constructor.prototype)
+         return true;
+      if (typeof object == 'xml') {
+        return constructor.prototype == XML.prototype;
+      }
+      object = object.__proto__;
+   }
+   return false;
+}
+
+ +
Зверніть увагу, що: ця реалізація додатково перевіряє відношення об'єкту до типу "xml",  щоб обійти особливість уявлення XML-об'єктіву останніх версіях JavaScript. Дивіться {{ bug(634150) }}, якщо вам потрібна докладніша інформація.
+ +

Наступні вирази із визначеною вище функцією instanceOf являються істинними:

+ +
instanceOf(chris, Engineer)
+instanceOf(chris, WorkerBee)
+instanceOf(chris, Employee)
+instanceOf(chris, Object)
+
+ +

Проте такий приклад в результаті видасть false:

+ +
instanceOf(chris, SalesPerson)
+
+ +

Глобальна інформація у конструкторах

+ +

Потрібно бути уважним при створенні конструкторів, якщо ви задаєте в них якісь глобальні дані. Наприклад, припустимо, нам потрібно автоматично задавати унікальний ID кожному новому робітнику. Ви можете об'явити Employee так:

+ +
var idCounter = 1;
+
+function Employee(name, dept) {
+   this.name = name || '';
+   this.dept = dept || 'general';
+   this.id = idCounter++;
+}
+
+ +

Згідно цього визначення Employee, під час створення нового екземпляру конструктор призначає йому наявний ID, і потім підвищує на 1 глобальний лічильник ID. Тобто, якщо виконати наступні інструкції, victoria.id буде 1, а harry.id — 2:

+ +
var victoria = new Employee('Pigbert, Victoria', 'pubs');
+var harry = new Employee('Tschopik, Harry', 'sales');
+
+ +

На перший погляд все чудово. Однак, idCounter змінюється кожного разу, коли створюється екземпляр Employee, байдуже для чого. Якщо створити всю ієрархію Employee, наведену у цьому розділі, конструктор Employee буде викликано кожного разу при заданні прототипу. Припустимо, у нас є наступний код:

+ +
var idCounter = 1;
+
+function Employee(name, dept) {
+   this.name = name || '';
+   this.dept = dept || 'general';
+   this.id = idCounter++;
+}
+
+function Manager(name, dept, reports) {...}
+Manager.prototype = new Employee;
+
+function WorkerBee(name, dept, projs) {...}
+WorkerBee.prototype = new Employee;
+
+function Engineer(name, projs, mach) {...}
+Engineer.prototype = new WorkerBee;
+
+function SalesPerson(name, projs, quota) {...}
+SalesPerson.prototype = new WorkerBee;
+
+var mac = new Engineer('Wood, Mac');
+
+ +

Далі припустимо, що визначення, що опущені тут мають властивість base і викликають констуктор, що знаходиться вище у ланцюжку прототипів. У цьому випадку, у момент створення об'єкту mac, mac.id буде 5.

+ +

Залежно від застосування, таке додаткове збільшення лічильника може мати, чи не мати значення. Якщо для вас важливе справжнє значення лічильника, один із варіантів рішення матиме такий вигляд конструктора:

+ +
function Employee(name, dept) {
+   this.name = name || '';
+   this.dept = dept || 'general';
+   if (name)
+      this.id = idCounter++;
+}
+
+ +

При створенні екземпляру Employee для застосування в якості прототипу аргументи не задаються. Згідно цього визначення конструктора, коли ми не передаємо аргументи, конструктор не задає значення id та не оновлює лічильник. Таким чином, щоб отримати Employee із призначеним id, необхідно задати ім'я робітника. У цьому випадку mac.id буде дорівнювати 1.

+ +

Інший варіант  створювати копію об'єкту-прототипу Employee, щоб потім присвоювати її WorkerBee:

+ +
WorkerBee.prototype = Object.create(Employee.prototype);
+// instead of WorkerBee.prototype = new Employee
+
+ +

Відсутність множинного успадкування

+ +

Деякі об'єктно-орієнтовані мови програмування дозволяють множинне успадкування. Це означає, що об'єкт може наслідувати поля і властивості від незалежних батьківських об'єктів. JavaScript не підтримує такий тип наслідування.

+ +

Наслідування значення властивості відбувається в момент виконання програми, коли JavaScript шукає значення властивості у ланцюжку прототипів об'єкту. Так як об'єкт має лише один прототип, JavaScript не може виконувати наслідування від більш ніж одного прототипного ланцюжка.

+ +

У JavaScript ми можемо мати функцію-конструктор, що викликає два чи більше інших конструкторів під час виконання. Це дає певну ілюзію множинного наслідування. Наприклад, припустимо, у нас є такі інструкції:

+ +
function Hobbyist(hobby) {
+   this.hobby = hobby || 'scuba';
+}
+
+function Engineer(name, projs, mach, hobby) {
+   this.base1 = WorkerBee;
+   this.base1(name, 'engineering', projs);
+   this.base2 = Hobbyist;
+   this.base2(hobby);
+   this.machine = mach || '';
+}
+Engineer.prototype = new WorkerBee;
+
+var dennis = new Engineer('Doe, Dennis', ['collabra'], 'hugo');
+
+ +

Далі припустимо, що визначення WorkerBee відповідає вказаному вище у розділі. У цьому випадку об'ект dennis матиме такі значення властивостей:

+ +
dennis.name == 'Doe, Dennis';
+dennis.dept == 'engineering';
+dennis.projects == ['collabra'];
+dennis.machine == 'hugo';
+dennis.hobby == 'scuba';
+
+ +

Тобто dennis отримує поле hobby з конструктора Hobbyist. Однак, якщо ми потім додамо нову властивість до прототипу конструктора Hobbyist:

+ +
Hobbyist.prototype.equipment = ['mask', 'fins', 'regulator', 'bcd'];
+
+ +

Об'єкт dennis не успадковує цю нову властивість.

+ +
{{PreviousNext("Web/JavaScript/Guide/Working_with_Objects", "Web/JavaScript/Guide/Using_promises")}}
diff --git a/files/uk/web/javascript/guide/functions/index.html b/files/uk/web/javascript/guide/functions/index.html new file mode 100644 index 0000000000..fcc14568b3 --- /dev/null +++ b/files/uk/web/javascript/guide/functions/index.html @@ -0,0 +1,655 @@ +--- +title: Функції +slug: Web/JavaScript/Guide/Functions +translation_of: Web/JavaScript/Guide/Functions +--- +

{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Вирази_та_оператори")}}

+ +

Функції є одним з фундаментальних блоків у JavaScript. Функція є процедурою JavaScript, це набір команд, які виконують ту чи іншу задачу, або розраховують значення. Щоб використати функцію, ви маєте десь її визначити у тій області видимості, звідки ви бажаєте її викликати.

+ +

Щоб дізнатись більше, дивіться exhaustive reference chapter about JavaScript functions.

+ +

Визначення функції

+ +

Оголошення функції

+ +

Визначення функції (також називається оголошенням функції, або функціональним оператором) складається з ключового слова function , після чого слідує:

+ + + +

Для прикладу, наступний код визначає просту функцію на ім'я square:

+ +
function square(number) {
+  return number * number;
+}
+ +

Функція square приймає один параметр number. Функція складається з однієї команди, що повертає результат множення агрумента (number) самого на себе. Оператор return визначає, яке значення повертає функція:

+ +
return number * number;
+
+ +

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

+ +

Якщо ви передаєте об'єкт (тобто, непримітивне значення, наприклад, {{jsxref ("Array")}} або визначений користувачем об'єкт) у якості параметра, і функція змінює властивості об'єкта, ця зміна видима за межами функції, як показано на наступному прикладі:

+ +
function myFunc(theObject) {
+  theObject.make = 'Toyota';
+}
+
+var mycar = {make: 'Honda', model: 'Accord', year: 1998};
+var x, y;
+
+x = mycar.make; // x отримує значення "Honda"
+
+myFunc(mycar);
+y = mycar.make; // y отримує значення "Toyota"
+                // (властивість make була змінена функцією)
+
+ +

Функціональні вирази

+ +

Хоча оголошення функцій вище синтаксично є виразом, функції також можуть бути створені за допомогою функціональних виразів. Така функція може бути анонімною; їй не обов'язково мати ім'я. Наприклад, square можна визначити як:

+ +
var square = function(number) { return number * number; };
+var x = square(4); // x gets the value 16
+ +

Проте, ім'я може бути надане у функціональному виразі, і може бути використане всередині функції, щоб звернутися до самої себе, або в налагоджувач, щоб визначити функцію в трасуванні стеку:

+ +
var factorial = function fac(n) { return n < 2 ? 1 : n * fac(n - 1); };
+
+console.log(factorial(3));
+
+ +

Функціональні вирази зручні при передачі функції як аргументу до іншої функції. Наступний приклад показує функцію map, яка повинна отримати функцію як перший аргумент, а масив як другий аргумент.

+ +
function map(f, a) {
+  var result = [], // Створення нового масиву
+      i;
+  for (i = 0; i != a.length; i++)
+    result[i] = f(a[i]);
+  return result;
+}
+
+ +

У наступному коді наша функція приймає функцію, визначену функціональним виразом, та виконує її для кожного елемента масиву, отриманого в якості другого аргументу.

+ +
function map(f, a) {
+  var result = []; // Створення нового масиву
+  var i; //  Оголошення змінної
+  for (i = 0; i != a.length; i++)
+    result[i] = f(a[i]);
+      return result;
+}
+var f = function(x) {
+   return x * x * x;
+}
+var numbers = [0,1, 2, 5,10];
+var cube = map(f,numbers);
+console.log(cube);
+ +

Функція повертає: [0, 1, 8, 125, 1000].

+ +

У JavaScript функція може бути визначена на основі умови. Наприклад, наступне визначення функції визначає myFunc тільки якщо num дорівнює 0:

+ +
var myFunc;
+if (num === 0) {
+  myFunc = function(theObject) {
+    theObject.make = 'Toyota';
+  }
+}
+ +

На додаток до визначення функцій, як описано тут, ви також можете використовувати конструктор {{jsxref ("Function")}} для створення функцій з текстового рядка під час виконання, як і {{jsxref("eval", "eval()")}}.

+ +

Метод - це функція, яка є властивістю об'єкта. Докладніше про об'єкти та методи у  Working with objects.

+ +

Виклик функцій

+ +

Визначення функції не виконує її. Визначення функції просто називає функцію і вказує, що робити, коли викликається функція. Виклик функції, власне, виконує вказані дії з вказаними параметрами. Наприклад, якщо ви визначили функцію  square, ви можете викликати її наступним чином:

+ +
square(5);
+
+ +

Наведений вираз викликає функцію з аргументом 5. Функція виконує свої команди та повертає значення 25.

+ +

Функції повинні бути в області видимості під час виклику, але оголошення функції може підніматись (бути записаним нижче виклику), як у цьому прикладі:

+ +
console.log(square(5));
+/* ... */
+function square(n) { return n * n; }
+
+ +

Областю видимості функції є функція, в якій вона оголошена, або вся програма, якщо вона оголошена на верхньому рівні.

+ +
+

Примітка: Це працює тільки при визначенні функції за допомогою наведеного вище синтаксису (тобто function funcName(){}). Наведений нижче код не буде працювати. Це означає, що підняття функції працює тільки для оголошення функції, а не для функціонального виразу.

+
+ +
console.log(square); // square піднімається з початковим значенням undefined.
+console.log(square(5)); // TypeError: square is not a function
+var square = function(n) {
+  return n * n;
+}
+
+ +

Аргументи функції не обмежені рядками та числами. Ви можете передавати цілі об'єкти у функцію. Функція show_props() (визначена у Working with objects) є прикладом функції, яка приймає об'єкт у якості аргумента.

+ +

Функція може викликати сама себе. Наприклад, ось функція, яка обчислює факторіал рекурсивно:

+ +
function factorial(n) {
+  if ((n === 0) || (n === 1))
+    return 1;
+  else
+    return (n * factorial(n - 1));
+}
+
+ +

Далі ви можете обчислити факторіали від одного до п'яти наступним чином:

+ +
var a, b, c, d, e;
+a = factorial(1); // a отримує значення 1
+b = factorial(2); // b отримує значення 2
+c = factorial(3); // c отримує значення 6
+d = factorial(4); // d отримує значення 24
+e = factorial(5); // e отримує значення 120
+
+ +

Є й інші способи виклику функцій. Часто бувають випадки, коли функцію потрібно назвати динамічно, або кількість аргументів функції може змінюватись, або контекстом виклику функції повинен бути заданий певний об'єкт, визначений під час виконання. Виявляється, що функції самі є об'єктами, і ці об'єкти, у свою чергу, мають методи (див. об'єкт {{jsxref("Function")}}). Один з них, метод {{jsxref("Function.apply", "apply()")}} , може бути використаний для досягнення цієї мети.

+ +

Область видимості функції

+ +

Змінні, визначені всередині функції, недоступні ззовні цієї функції, бо змінна визначається тільки у області видимості функції. Проте, функція може звертатись до усіх змінних та функцій, визначених у області видимості, де вона оголошена. Іншими словами, функція, оголошена у глобальній області видимості, може звертатись до усіх змінних, оголошених у глобальній області видимості. Функція, оголошена всередині іншої функції, має доступ до усіх змінних, оголошених у батьківській функції, а також до будь-якої змінної, до якої має доступ батьківська функція.

+ +
// Ці змінні визначені у глобальній області видимості
+var num1 = 20,
+    num2 = 3,
+    name = 'Chamahk';
+
+// Ця функція визначена у глобальній області видимості
+function multiply() {
+  return num1 * num2;
+}
+
+multiply(); // Повертає 60
+
+// Приклад вкладеної функції
+function getScore() {
+  var num1 = 2,
+      num2 = 3;
+
+  function add() {
+    return name + ' scored ' + (num1 + num2);
+  }
+
+  return add();
+}
+
+getScore(); // Повертає "Chamahk scored 5"
+
+ +

Область видимості та стек функції

+ +

Рекурсія

+ +

A function can refer to and call itself. There are three ways for a function to refer to itself:

+ +
    +
  1. the function's name
  2. +
  3. arguments.callee
  4. +
  5. an in-scope variable that refers to the function
  6. +
+ +

For example, consider the following function definition:

+ +
var foo = function bar() {
+   // statements go here
+};
+
+ +

Within the function body, the following are all equivalent:

+ +
    +
  1. bar()
  2. +
  3. arguments.callee()
  4. +
  5. foo()
  6. +
+ +

A function that calls itself is called a recursive function. In some ways, recursion is analogous to a loop. Both execute the same code multiple times, and both require a condition (to avoid an infinite loop, or rather, infinite recursion in this case). For example, the following loop:

+ +
var x = 0;
+while (x < 10) { // "x < 10" is the loop condition
+   // do stuff
+   x++;
+}
+
+ +

can be converted into a recursive function and a call to that function:

+ +
function loop(x) {
+  if (x >= 10) // "x >= 10" is the exit condition (equivalent to "!(x < 10)")
+    return;
+  // do stuff
+  loop(x + 1); // the recursive call
+}
+loop(0);
+
+ +

However, some algorithms cannot be simple iterative loops. For example, getting all the nodes of a tree structure (e.g. the DOM) is more easily done using recursion:

+ +
function walkTree(node) {
+  if (node == null) //
+    return;
+  // do something with node
+  for (var i = 0; i < node.childNodes.length; i++) {
+    walkTree(node.childNodes[i]);
+  }
+}
+
+ +

Compared to the function loop, each recursive call itself makes many recursive calls here.

+ +

It is possible to convert any recursive algorithm to a non-recursive one, but often the logic is much more complex and doing so requires the use of a stack. In fact, recursion itself uses a stack: the function stack.

+ +

The stack-like behavior can be seen in the following example:

+ +
function foo(i) {
+  if (i < 0)
+    return;
+  console.log('begin: ' + i);
+  foo(i - 1);
+  console.log('end: ' + i);
+}
+foo(3);
+
+// Output:
+
+// begin: 3
+// begin: 2
+// begin: 1
+// begin: 0
+// end: 0
+// end: 1
+// end: 2
+// end: 3
+ +

Nested functions and closures

+ +

You can nest a function within a function. The nested (inner) function is private to its containing (outer) function. It also forms a closure. A closure is an expression (typically a function) that can have free variables together with an environment that binds those variables (that "closes" the expression).

+ +

Since a nested function is a closure, this means that a nested function can "inherit" the arguments and variables of its containing function. In other words, the inner function contains the scope of the outer function.

+ +

To summarize:

+ + + + + +

The following example shows nested functions:

+ +
function addSquares(a, b) {
+  function square(x) {
+    return x * x;
+  }
+  return square(a) + square(b);
+}
+a = addSquares(2, 3); // returns 13
+b = addSquares(3, 4); // returns 25
+c = addSquares(4, 5); // returns 41
+
+ +

Since the inner function forms a closure, you can call the outer function and specify arguments for both the outer and inner function:

+ +
function outside(x) {
+  function inside(y) {
+    return x + y;
+  }
+  return inside;
+}
+fn_inside = outside(3); // Think of it like: give me a function that adds 3 to whatever you give it
+result = fn_inside(5); // returns 8
+
+result1 = outside(3)(5); // returns 8
+
+ +

Preservation of variables

+ +

Notice how x is preserved when inside is returned. A closure must preserve the arguments and variables in all scopes it references. Since each call provides potentially different arguments, a new closure is created for each call to outside. The memory can be freed only when the returned inside is no longer accessible.

+ +

This is not different from storing references in other objects, but is often less obvious because one does not set the references directly and cannot inspect them.

+ +

Multiply-nested functions

+ +

Functions can be multiply-nested, i.e. a function (A) containing a function (B) containing a function (C). Both functions B and C form closures here, so B can access A and C can access B. In addition, since C can access B which can access A, C can also access A. Thus, the closures can contain multiple scopes; they recursively contain the scope of the functions containing it. This is called scope chaining. (Why it is called "chaining" will be explained later.)

+ +

Consider the following example:

+ +
function A(x) {
+  function B(y) {
+    function C(z) {
+      console.log(x + y + z);
+    }
+    C(3);
+  }
+  B(2);
+}
+A(1); // logs 6 (1 + 2 + 3)
+
+ +

In this example, C accesses B's y and A's x. This can be done because:

+ +
    +
  1. B forms a closure including A, i.e. B can access A's arguments and variables.
  2. +
  3. C forms a closure including B.
  4. +
  5. Because B's closure includes A, C's closure includes A, C can access both B and A's arguments and variables. In other words, C chains the scopes of B and A in that order.
  6. +
+ +

The reverse, however, is not true. A cannot access C, because A cannot access any argument or variable of B, which C is a variable of. Thus, C remains private to only B.

+ +

Name conflicts

+ +

When two arguments or variables in the scopes of a closure have the same name, there is a name conflict. More inner scopes take precedence, so the inner-most scope takes the highest precedence, while the outer-most scope takes the lowest. This is the scope chain. The first on the chain is the inner-most scope, and the last is the outer-most scope. Consider the following:

+ +
function outside() {
+  var x = 5;
+  function inside(x) {
+    return x * 2;
+  }
+  return inside;
+}
+
+outside()(10); // returns 20 instead of 10
+
+ +

The name conflict happens at the statement return x and is between inside's parameter x and outside's variable x. The scope chain here is {inside, outside, global object}. Therefore inside's x takes precedences over outside's x, and 20 (inside's x) is returned instead of 10 (outside's x).

+ +

Closures

+ +

Closures are one of the most powerful features of JavaScript. JavaScript allows for the nesting of functions and grants the inner function full access to all the variables and functions defined inside the outer function (and all other variables and functions that the outer function has access to). However, the outer function does not have access to the variables and functions defined inside the inner function. This provides a sort of encapsulation for the variables of the inner function. Also, since the inner function has access to the scope of the outer function, the variables and functions defined in the outer function will live longer than the duration of the inner function execution, if the inner function manages to survive beyond the life of the outer function. A closure is created when the inner function is somehow made available to any scope outside the outer function.

+ +
var pet = function(name) {   // The outer function defines a variable called "name"
+  var getName = function() {
+    return name;             // The inner function has access to the "name" variable of the outer function
+  }
+  return getName;            // Return the inner function, thereby exposing it to outer scopes
+}
+myPet = pet('Vivie');
+
+myPet();                     // Returns "Vivie"
+
+ +

It can be much more complex than the code above. An object containing methods for manipulating the inner variables of the outer function can be returned.

+ +
var createPet = function(name) {
+  var sex;
+
+  return {
+    setName: function(newName) {
+      name = newName;
+    },
+
+    getName: function() {
+      return name;
+    },
+
+    getSex: function() {
+      return sex;
+    },
+
+    setSex: function(newSex) {
+      if(typeof newSex === 'string' && (newSex.toLowerCase() === 'male' || newSex.toLowerCase() === 'female')) {
+        sex = newSex;
+      }
+    }
+  }
+}
+
+var pet = createPet('Vivie');
+pet.getName();                  // Vivie
+
+pet.setName('Oliver');
+pet.setSex('male');
+pet.getSex();                   // male
+pet.getName();                  // Oliver
+
+ +

In the code above, the name variable of the outer function is accessible to the inner functions, and there is no other way to access the inner variables except through the inner functions. The inner variables of the inner functions act as safe stores for the outer arguments and variables. They hold "persistent" and "encapsulated" data for the inner functions to work with. The functions do not even have to be assigned to a variable, or have a name.

+ +
var getCode = (function() {
+  var apiCode = '0]Eal(eh&2';    // A code we do not want outsiders to be able to modify...
+
+  return function() {
+    return apiCode;
+  };
+}());
+
+getCode();    // Returns the apiCode
+
+ +

There are, however, a number of pitfalls to watch out for when using closures. If an enclosed function defines a variable with the same name as the name of a variable in the outer scope, there is no way to refer to the variable in the outer scope again.

+ +
var createPet = function(name) {  // Outer function defines a variable called "name"
+  return {
+    setName: function(name) {    // Enclosed function also defines a variable called "name"
+      name = name;               // ??? How do we access the "name" defined by the outer function ???
+    }
+  }
+}
+
+ +

Using the arguments object

+ +

The arguments of a function are maintained in an array-like object. Within a function, you can address the arguments passed to it as follows:

+ +
arguments[i]
+
+ +

where i is the ordinal number of the argument, starting at zero. So, the first argument passed to a function would be arguments[0]. The total number of arguments is indicated by arguments.length.

+ +

Using the arguments object, you can call a function with more arguments than it is formally declared to accept. This is often useful if you don't know in advance how many arguments will be passed to the function. You can use arguments.length to determine the number of arguments actually passed to the function, and then access each argument using the arguments object.

+ +

For example, consider a function that concatenates several strings. The only formal argument for the function is a string that specifies the characters that separate the items to concatenate. The function is defined as follows:

+ +
function myConcat(separator) {
+   var result = ''; // initialize list
+   var i;
+   // iterate through arguments
+   for (i = 1; i < arguments.length; i++) {
+      result += arguments[i] + separator;
+   }
+   return result;
+}
+
+ +

You can pass any number of arguments to this function, and it concatenates each argument into a string "list":

+ +
// returns "red, orange, blue, "
+myConcat(', ', 'red', 'orange', 'blue');
+
+// returns "elephant; giraffe; lion; cheetah; "
+myConcat('; ', 'elephant', 'giraffe', 'lion', 'cheetah');
+
+// returns "sage. basil. oregano. pepper. parsley. "
+myConcat('. ', 'sage', 'basil', 'oregano', 'pepper', 'parsley');
+
+ +
+

Note: The arguments variable is "array-like", but not an array. It is array-like in that it has a numbered index and a length property. However, it does not possess all of the array-manipulation methods.

+
+ +

See the {{jsxref("Function")}} object in the JavaScript reference for more information.

+ +

Function parameters

+ +

Starting with ECMAScript 2015, there are two new kinds of parameters: default parameters and rest parameters.

+ +

Default parameters

+ +

In JavaScript, parameters of functions default to undefined. However, in some situations it might be useful to set a different default value. This is where default parameters can help.

+ +

In the past, the general strategy for setting defaults was to test parameter values in the body of the function and assign a value if they are undefined. If in the following example, no value is provided for b in the call, its value would be undefined when evaluating a*b and the call to multiply would have returned NaN. However, this is caught with the second line in this example:

+ +
function multiply(a, b) {
+  b = typeof b !== 'undefined' ?  b : 1;
+
+  return a * b;
+}
+
+multiply(5); // 5
+
+ +

With default parameters, the check in the function body is no longer necessary. Now, you can simply put 1 as the default value for b in the function head:

+ +
function multiply(a, b = 1) {
+  return a * b;
+}
+
+multiply(5); // 5
+ +

For more details, see default parameters in the reference.

+ +

Rest parameters

+ +

The rest parameter syntax allows us to represent an indefinite number of arguments as an array. In the example, we use the rest parameters to collect arguments from the second one to the end. We then multiply them by the first one. This example is using an arrow function, which is introduced in the next section.

+ +
function multiply(multiplier, ...theArgs) {
+  return theArgs.map(x => multiplier * x);
+}
+
+var arr = multiply(2, 1, 2, 3);
+console.log(arr); // [2, 4, 6]
+ +

Arrow functions

+ +

An arrow function expression (previously, and now incorrectly known as fat arrow function) has a shorter syntax compared to function expressions and lexically binds the this value. Arrow functions are always anonymous. See also this hacks.mozilla.org blog post: "ES6 In Depth: Arrow functions".

+ +

Two factors influenced the introduction of arrow functions: shorter functions and lexical this.

+ +

Shorter functions

+ +

In some functional patterns, shorter functions are welcome. Compare:

+ +
var a = [
+  'Hydrogen',
+  'Helium',
+  'Lithium',
+  'Beryllium'
+];
+
+var a2 = a.map(function(s) { return s.length; });
+
+console.log(a2); // logs [8, 6, 7, 9]
+
+var a3 = a.map(s => s.length);
+
+console.log(a3); // logs [8, 6, 7, 9]
+
+ +

Lexical this

+ +

Until arrow functions, every new function defined its own this value (a new object in case of a constructor, undefined in strict mode function calls, the context object if the function is called as an "object method", etc.). This proved to be annoying with an object-oriented style of programming.

+ +
function Person() {
+  // The Person() constructor defines `this` as itself.
+  this.age = 0;
+
+  setInterval(function growUp() {
+    // In nonstrict mode, the growUp() function defines `this`
+    // as the global object, which is different from the `this`
+    // defined by the Person() constructor.
+    this.age++;
+  }, 1000);
+}
+
+var p = new Person();
+ +

In ECMAScript 3/5, this issue was fixed by assigning the value in this to a variable that could be closed over.

+ +
function Person() {
+  var self = this; // Some choose `that` instead of `self`.
+                   // Choose one and be consistent.
+  self.age = 0;
+
+  setInterval(function growUp() {
+    // The callback refers to the `self` variable of which
+    // the value is the expected object.
+    self.age++;
+  }, 1000);
+}
+ +

Alternatively, a bound function could be created so that the proper this value would be passed to the growUp() function.

+ +

Arrow functions capture the this value of the enclosing context, so the following code works as expected.

+ +
function Person() {
+  this.age = 0;
+
+  setInterval(() => {
+    this.age++; // |this| properly refers to the person object
+  }, 1000);
+}
+
+var p = new Person();
+ +

Predefined functions

+ +

JavaScript has several top-level, built-in functions:

+ +
+
{{jsxref("Global_Objects/eval", "eval()")}}
+
+

The eval() method evaluates JavaScript code represented as a string.

+
+
{{jsxref("Global_Objects/uneval", "uneval()")}} {{non-standard_inline}}
+
+

The uneval() method creates a string representation of the source code of an {{jsxref("Object")}}.

+
+
{{jsxref("Global_Objects/isFinite", "isFinite()")}}
+
+

The global isFinite() function determines whether the passed value is a finite number. If needed, the parameter is first converted to a number.

+
+
{{jsxref("Global_Objects/isNaN", "isNaN()")}}
+
+

The isNaN() function determines whether a value is {{jsxref("Global_Objects/NaN", "NaN")}} or not. Note: coercion inside the isNaN function has interesting rules; you may alternatively want to use {{jsxref("Number.isNaN()")}}, as defined in ECMAScript 2015, or you can use typeof to determine if the value is Not-A-Number.

+
+
{{jsxref("Global_Objects/parseFloat", "parseFloat()")}}
+
+

The parseFloat() function parses a string argument and returns a floating point number.

+
+
{{jsxref("Global_Objects/parseInt", "parseInt()")}}
+
+

The parseInt() function parses a string argument and returns an integer of the specified radix (the base in mathematical numeral systems).

+
+
{{jsxref("Global_Objects/decodeURI", "decodeURI()")}}
+
+

The decodeURI() function decodes a Uniform Resource Identifier (URI) previously created by {{jsxref("Global_Objects/encodeURI", "encodeURI")}} or by a similar routine.

+
+
{{jsxref("Global_Objects/decodeURIComponent", "decodeURIComponent()")}}
+
+

The decodeURIComponent() method decodes a Uniform Resource Identifier (URI) component previously created by {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} or by a similar routine.

+
+
{{jsxref("Global_Objects/encodeURI", "encodeURI()")}}
+
+

The encodeURI() method encodes a Uniform Resource Identifier (URI) by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two "surrogate" characters).

+
+
{{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent()")}}
+
+

The encodeURIComponent() method encodes a Uniform Resource Identifier (URI) component by replacing each instance of certain characters by one, two, three, or four escape sequences representing the UTF-8 encoding of the character (will only be four escape sequences for characters composed of two "surrogate" characters).

+
+
{{jsxref("Global_Objects/escape", "escape()")}} {{deprecated_inline}}
+
+

The deprecated escape() method computes a new string in which certain characters have been replaced by a hexadecimal escape sequence. Use {{jsxref("Global_Objects/encodeURI", "encodeURI")}} or {{jsxref("Global_Objects/encodeURIComponent", "encodeURIComponent")}} instead.

+
+
{{jsxref("Global_Objects/unescape", "unescape()")}} {{deprecated_inline}}
+
+

The deprecated unescape() method computes a new string in which hexadecimal escape sequences are replaced with the character that it represents. The escape sequences might be introduced by a function like {{jsxref("Global_Objects/escape", "escape")}}. Because unescape() is deprecated, use {{jsxref("Global_Objects/decodeURI", "decodeURI()")}} or {{jsxref("Global_Objects/decodeURIComponent", "decodeURIComponent")}} instead.

+
+
+ +

{{PreviousNext("Web/JavaScript/Guide/Loops_and_iteration", "Web/JavaScript/Guide/Вирази_та_оператори")}}

diff --git a/files/uk/web/javascript/guide/grammar_and_types/index.html b/files/uk/web/javascript/guide/grammar_and_types/index.html new file mode 100644 index 0000000000..415aaaff62 --- /dev/null +++ b/files/uk/web/javascript/guide/grammar_and_types/index.html @@ -0,0 +1,716 @@ +--- +title: Граматика та типи +slug: Web/JavaScript/Guide/Grammar_and_types +tags: + - JavaScript + - 'l10n:priority' + - Посібник +translation_of: Web/JavaScript/Guide/Grammar_and_types +--- +

{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}

+ +

В цьому розділі розглядаються основи граматики JavaScript, оголошення змінних, типи даних і літерали.

+ +

Основи

+ +

Більшість свого синтаксису JavaScript запозичає у Java, C та C++, але на нього вплинули також Awk, Perl і Python.

+ +

Мова JavaScript чутлива до регістру і використовує набір символів Unicode. Наприклад, слово Früh (що німецькою означає "рано") може використовуватись як ім'я змінної.

+ +
let Früh = "foobar"
+ +

Проте, змінна früh не одне й те саме, що Früh, тому що мова JavaScript чутлива до регістру.

+ +

У JavaScript команди називаються інструкціями і розділяються крапкою з комою (;).

+ +

Немає необхідності ставити крапку з комою після інструкції, якщо вона написана на своєму власному рядку. Проте, якщо ви бажаєте мати більш, ніж одну інструкцію в рядку, тоді потрібно їх відділяти крапкою з комою.

+ +
+

ECMAScript також має правила для автоматичної вставки крапки з комою (ASI, Automatic semicolon insertion) в кінці інструкцій. (Щоб отримати більше інформації, перегляньте детальну довідку щодо лексичної граматики JavaScript.)

+
+ +

Однак, вважається найкращою практикою завжди ставити крапку з комою після інструкції, навіть якщо вона не вимагається. Ця практика зменшує шанси отримати помилки у коді.

+ +

Текст скрипта у JavaScript сканується зліва направо та конвертується у послідовність вхідних елементів, якими є токени, керівні символи, символи розриву рядка, коментарі, або пробільні символи. (Символи пробілів, табуляції та символи нового рядка вважаються пробільними символами).

+ +

Коментарі

+ +

Синтаксис коментарів такий самий, як у C++ та багатьох інших мовах програмування:

+ +
// однорядковий коментар
+
+/* а це довший,
+* багаторядковий коментар
+*/
+
+/* Однак, не можна, /* вкладати коментарі */ SyntaxError */
+ +

Коментарі поводяться як пробіли та відкидаються під час виконання скрипта.

+ +
+

Заувага: Ви можете також побачити третій тип синтаксису коментарів на початку деяких файлів JavaScript, який виглядає приблизно так: #!/usr/bin/env node.

+ +

Цей синтаксис називається шебанг, це спеціальний коментар, який використовується, щоб вказати шлях до певного рушія JavaScript, який має виконати скрипт. Дивіться коментарі шебанг для більш детальної інформації.

+
+ +

Оголошення

+ +

Існують три види оголошення змінних у JavaScript.

+ +
+
{{jsxref("Statements/var", "var")}}
+
Оголошує змінну та необов'язково ініціалізує її значенням.
+
{{jsxref("Statements/let", "let")}}
+
Оголошує локальну змінну блочної області видимості, необов'язково ініціалізуючи її значенням.
+
{{jsxref("Statements/const","const")}}
+
Оголошує константу блочної області видимості, доступну тільки для читання.
+
+ +

Змінні

+ +

Ви використовуєте змінні, як символічні імена для значень у вашій програмі. Назви змінних, ідентифікатори, відповідають певним правилам.

+ +

Ідентифікатори JavaScript повинні починатися з літери, знаку підкреслення (_) або знаку долара ($). Наступні символи можуть також бути цифрами (0-9).

+ +

Оскільки мова JavaScript чутлива до регістру, літери включають у себе символи від "A" до "Z" (у верхньому регістрі) та символи від  "a" до "z" (у нижньому регістрі).

+ +

Ви можете використовувати більшу частину літер ISO 8859-1 або Юнікоду, такі як å та ü у ідентифікаторах. (Для більш детальної інформації дивіться цю статтю.) Ви також можете використовувати екрановані послідовності Юнікоду в якості символів у ідентифікаторах.

+ +

Деякі приклади допустимих назв: Number_hits, temp99, $credit та _name.

+ +

Оголошення змінних

+ +

Ви можете оголосити змінну двома шляхами:

+ + + +

Ви також можете просто присвоїти змінній значення. Наприклад, x = 42. Ця форма створює неоголошену глобальну змінну. Вона також генерує попередження у JavaScript. Неоголошені глобальні змінні можуть привести до неочікуваної поведінки. Тому не рекомендується використовувати неоголошені глобальні змінні.

+ +

Обчислення змінних

+ +

Змінна, оголошена за допомогою var або let, без початкового значення, має значення {{jsxref("undefined")}}.

+ +

Спроба звернення до неоголошеної змінної призведе до викидання винятку {{jsxref("ReferenceError")}}:

+ +
var a;
+console.log('Значення a дорівнює ' + a); // Значення a дорівнює undefined
+
+console.log('Значення b дорівнює ' + b); // Значення b дорівнює undefined
+var b;
+// Це може спантеличити, доки ви не прочитаєте 'Підняття змінних' нижче
+
+console.log('Значення c дорівнює ' + c); // Uncaught ReferenceError: c is not defined
+
+let x;
+console.log('Значення x дорівнює ' + x); // Значення x дорівнює undefined
+
+console.log('Значення y дорівнює ' + y); // Uncaught ReferenceError: y is not defined
+let y; 
+ +

Можна використати undefined, щоб з'ясувати, чи має змінна значення. У наступному коді змінній input не присвоюється значення, і умова в операторі if набуває значення true.

+ +
var input;
+if (input === undefined) {
+  doThis();
+} else {
+  doThat();
+}
+ +

Значення undefined поводить себе як false, коли використовується в булевому контексті. Наприклад, наступний код виконує функцію myFunction, оскільки елемент myArray дорівнює undefined:

+ +
var myArray = [];
+if (!myArray[0]) myFunction(); 
+ +

Значення undefined перетворюється на NaN, коли використовується у числовому контексті.

+ +
var a;
+a + 2;  // Обчислюється як NaN
+ +

Коли ви обчислюєте змінну {{jsxref("null")}}, значення null поводить себе як 0 у числовому контексті, та як false - у булевому. Наприклад:

+ +
var n = null;
+console.log(n * 32); // Виведе 0 у консоль
+ +

 Область видимості змінної

+ +

Коли ви оголошуєте змінну за межами будь-яких функцій, вона називається глобальною змінною, позаяк доступна для будь-якого іншого коду у поточному документі. Коли ви оголошуєте змінну всередині функції, вона називається локальною змінною, позаяк доступна лише в межах цієї функції.

+ +

JavaScript до ECMAScript 2015 не має блочної області видимості. Точніше, змінна, оголошена всередині блоку, є локальною для функції (або глобальної області видимості), в якій розміщено цей блок.

+ +

Наприклад, наступний код виведе 5, тому що областю видимості x є глобальний контекст (або контекст функції, якщо код є частиною функції). Область видимості x не обмежується найближчим блоком конструкції if.

+ +
if (true) {
+  var x = 5;
+}
+console.log(x);  // x дорівнює 5
+ +

Ця поведінка змінюється при використанні ключового слова let, (представленого в ECMAScript 2015).

+ +
if (true) {
+  let y = 5;
+}
+console.log(y);  // ReferenceError: y is not defined
+ +

Підняття змінних

+ +

Ще однією особливістю змінних у JavaScript є те, що ви можете посилатися на змінну, оголошену пізніше, і це не призведе до винятку.

+ +

Ця концепція має назву підняття (hoisting). Змінні у JavaScript, в певному сенсі, "піднімаються" на вершину функції або інструкції у коді. Однак, підняті змінні повертають значення undefined. Тому, навіть якщо ви оголосите та ініціалізуєте змінну після використання або посилання на цю змінну, вона все одно поверне undefined.

+ +
/**
+* Приклад 1
+*/
+console.log(x === undefined); // true
+var x = 3;
+
+/**
+* Приклад 2
+*/
+// поверне значення undefined
+var myvar = 'моє значення';
+
+(function() {
+  console.log(myvar); // undefined
+  var myvar = 'локальна змінна';
+})();
+ +

Наведені вище приклади будуть тлумачитися так само, як:

+ +
/**
+* Приклад 1
+*/
+var x;
+console.log(x === undefined); // true
+x = 3;
+
+/**
+* Приклад 2
+*/
+var myvar = 'моє значення';
+
+(function() {
+  var myvar;
+  console.log(myvar); // undefined
+  myvar = 'локальна змінна';
+})();
+ +

Враховуючи підняття, всі оголошення через var всередині функції мають знаходитись якомога ближче до вершини функції. Така практика покращує зрозумілість коду.

+ +

В ECMAScript 2015 let та const підіймаються, але не ініціалізуються. Результатом посилання на змінну в блоці до оголошення цієї змінної буде {{jsxref("ReferenceError")}}, тому що змінна перебуває у "тимчасовій мертвій зоні" від початку блоку до обробки її оголошення.

+ +
console.log(x); // ReferenceError
+let x = 3;
+ +

Підняття функції

+ +

У випадку з функціями, лише оголошення функцій піднімаються, але не функціональні вирази.

+ +
/* Оголошення функції */
+
+foo(); // "ква"
+
+function foo() {
+  console.log('ква');
+}
+
+/* Функціональний вираз */
+
+baz(); // TypeError: baz is not a function
+
+var baz = function() {
+  console.log('кря');
+};
+ +

Глобальні змінні

+ +

Глобальні змінні насправді є властивостями глобального об'єкта.

+ +

На веб-сторінках глобальним об'єктом є window, тому ви можете присвоювати значення та звертатись до глобальних змінних за допомогою синтаксису window.змінна.

+ +

Відповідно, ви можете звертатись до глобальних змінних, оголошених в одному вікні або фреймі, з іншого вікна або фрейму, вказавши при цьому ім'я цього вікна чи фрейму. Наприклад, якщо в документі оголошена змінна під назвою phoneNumber, ви можете звернутися до неї з iframe так: parent.phoneNumber.

+ +

Константи

+ +

Ви можете створити іменовану константу, призначену лише для читання, за допомогою ключового слова {{jsxref("Statements/const", "const")}}.

+ +

Синтаксис ідентифікатора константи такий самий, як і синтаксис будь-якого ідентифікатора змінної: він повинен починатися з літери, підкреслення або знака долара ($) та може містити букви, цифри або символи підкреслення.

+ +
const PI = 3.14;
+ +

Константа не може змінювати значення за допомогою присвоювання або повторно оголошуватися протягом виконання скрипта. Вона повинна бути ініціалізована початковим значенням.

+ +

Правила області видимості для констант такі ж, як для let-змінних блочної області видимості. Якщо ключове слово const не вказане, ідентифікатор вважається ідентифікатором змінної.

+ +

Не можна оголошувати константу з таким самим ім'ям, як функція або змінна в тій самій області видимості. Наприклад:

+ +
// ЦЕ СПРИЧИНИТЬ ПОМИЛКУ
+function f() {};
+const f = 5;
+
+// ЦЕ ТАКОЖ СПРИЧИНИТЬ ПОМИЛКУ
+function f() {
+  const g = 5;
+  var g;
+
+  //інструкції
+}
+ +

Однак, властивості об'єктів, присвоєних константам, не захищені, тому наступна інструкція виконується без проблем.

+ +
const MY_OBJECT = {'key': 'значення'};
+MY_OBJECT.key = 'іншезначення';
+ +

Вміст будь-якого масиву також не захищений, тому наступна інструкція виконується без проблем.

+ +
const MY_ARRAY = ['HTML','CSS'];
+MY_ARRAY.push('JAVASCRIPT');
+console.log(MY_ARRAY); //виведе ['HTML','CSS','JAVASCRIPT'];
+
+ +

Структури та типи даних

+ +

Типи даних

+ +

Останній стандарт ECMAScript визначає вісім типів даних:

+ + + +

Хоча цих типів даних відносно мало, вони дозволяють виконувати корисні функції у ваших застосунках. {{jsxref("Object", "Об'єкти")}} та {{jsxref("Function", "функції")}} - це інші фундаментальні елементи мови. Об'єкти можна розглядати, як іменовані контейнери для значень, а функції - як процедури, які може виконувати скрипт. 

+ +

Перетворення типів даних

+ +

JavaScript - це мова з динамічною типізацією. Це означає, що при оголошенні змінної не потрібно вказувати, якого вона типу. Це також означає, що типи даних автоматично перетворюються за необхідності під час виконання скрипта. 

+ +

Наприклад, ви можете визначити змінну таким чином:

+ +
var answer = 42;
+ +

А пізніше цій же змінній можна присвоїти значення рядкового типу даних, наприклад:

+ +
answer = 'Дякуємо за рибу...';
+ +

Оскільки JavaScript динамічно типізована мова, таке присвоєння не спричиняє повідомлення про помилку.

+ +

Числа та оператор '+'

+ +

У виразах, що включають числові й рядкові значення з оператором +, JavaScript перетворює числові значення на рядки. Наприклад:

+ +
x = 'Відповідь - ' + 42 // "Відповідь - 42"
+y = 42 + ' - це відповідь' // "42 - це відповідь"
+ +

З усіма іншими операторами JavaScript не перетворює числові значення на рядки. Наприклад:

+ +
'37' - 7 // 30
+'37' + 7 // "377"
+ +

Перетворення рядків на числа

+ +

У випадку, коли значення, що представляє число, є в пам'яті у вигляді рядка, існують методи для перетворення.

+ + + +

parseInt повертає тільки цілі числа, тому його використання для десяткових чисел обмежене.

+ +
+

Крім того, найкращою практикою для parseInt є завжди включати параметр radix (основа). Параметр radix вказує, яка система числення має використовуватись.

+
+ +
parseInt('101', 2) // 5
+ +

Альтернативним методом отримання числа з рядка є використання оператора + (унарний плюс):

+ +
'1.1' + '1.1' // '1.11.1'
+(+'1.1') + (+'1.1') // 2.2
+// Зауважте: дужки не обов'язкові, вони додаються для ясності
+ +

Літерали

+ +

Літерали (англ. literal - "буквальний") відображають значення у JavaScript. Це фіксовані значення, не змінні, які ви буквально вказуєте у сценарії. У цьому розділі описані наступні типи літералів:

+ + + +

Масивові літерали

+ +

Масивовий літерал - це список з нуля чи більше виразів, які представляють елементи масиву, вкладений у квадратні дужки ([]). Коли ви створюєте масив, використовуючи масивовий літерал, він ініціалізується вказаними значеннями в якості своїх елементів, а його довжина дорівнює кількості вказаних аргументів.

+ +

Наступний приклад створює масив coffees (кава) з трьома елементами та довжиною, що дорівнює три:

+ +
let coffees = ['Французька', 'Колумбійська', 'Кона'];
+ +
+

Заувага: Літерал масиву - це тип об'єктного ініціалізатора. Дивіться Використання об'єктних ініціалізаторів.

+
+ +

Якщо масив створюється за допомогою літералів у скрипті верхнього рівня, JavaScript інтерпретує масив кожного разу, коли обчислює вираз, що містить літерал масиву. На додачу, літерал, що використовується у функції, створюється кожного разу, коли викликається функція.

+ +
+

Заувага:  Літерали масиву також є об'єктами Array. Більш детальну інформацію щодо об'єктів Array дивіться у статтях {{jsxref("Array")}} та Індексовані колекції.

+
+ +

Додаткові коми у масивних літералах

+ +

Вам не обов'язково вказувати всі елементи у масивному літералі. Якщо помістити дві коми поспіль, масив заповнить невказані елементи значеннями undefined. Наступний приклад створює масив fish (риба):

+ +
let fish = ['Крилатка', , 'Лящ'];
+ +

Цей масив має два елементи зі значеннями та один порожній елемент:

+ + + +

Якщо в кінці списку елементів ви додаєте кінцеву кому, вона ігнорується.

+ +

У наступному прикладі довжина масиву дорівнює трьом. Не існує елемента myList[3]. Усі інші коми у списку позначають новий елемент.

+ +
+

Заувага: коми в кінці можуть створювати помилки у старих версіях веб-переглядачів, тому краще їх видаляти.

+
+ +
let myList = ['дім', , 'школа', ];
+ +

У наступному прикладі довжина масиву становить чотири, а елементи myList[0] та myList[2] відсутні.

+ +
let myList = [ ,'дім', , 'школа'];
+ +

У наступному прикладі довжина масиву становить чотири, а елементи myList[1] та myList[3] відсутні. Ігнорується лише остання кома.

+ +
let myList = ['дім', , 'школа', , ];
+ +

Розуміння поведінки додаткових ком важливе для розуміння JavaScript як мови. 

+ +

Однак, при написанні власного коду, варто однозначно оголошувати відсутні елементи як undefined. Це підвищить зрозумілість та надійність вашого коду.

+ +

Булеві літерали

+ +

Тип Boolean має два значення літералів: true та false.

+ +
+

Будьте обережні: Не плутайте примітивні булеві значення true та false зі значеннями true та false об'єкта {{jsxref("Boolean")}}.

+Об'єкт Boolean - це обгортка навколо примітивного булевого типу даних. Дивіться {{jsxref("Boolean")}} для отримання додаткової інформації.
+ +

Числові літерали

+ +

Типи Number та BigInt можна виразити у десятковій (основа 10), шістнадцятковій (основа 16), вісімковій (основа 8) та двійковій (основа 2) формі.

+ + + +

Деякі приклади числових літералів:

+ +
0, 117, -345, 123456789123456789n             (десятковий, основа 10)
+015, 0001, -0o77, 0o777777777777n             (вісімковий, основа 8)
+0x1123, 0x00111, -0xF1A7, 0x123456789ABCDEFn  (шістнадцятковий, "hex" чи основа 16)
+0b11, 0b0011, -0b11, 0b11101001010101010101n  (двійковий, основа 2)
+ +

Для отримання додаткової інформації дивіться Числові літерали в довідці про лексичну граматику.

+ +

Літерали з рухомою крапкою

+ +

Літерал з рухомою крапкою може мати такі частини:

+ + + +

Порядок позначається через "e" або "E", за яким іде ціле число, яке може мати знак ("+" або "-" перед ним). Літерал з рухомою крапкою повинен мати принаймні одну цифру, а також або десяткову крапку, або "e" (чи "E").

+ +

Якщо стисло, синтаксис наступний:

+ +
[(+|-)][цифри].[цифри][(E|e)[(+|-)]цифри]
+ +

Наприклад:

+ +
3.1415926
+-.123456789
+-3.1E+12
+.1e-23
+ +

Об'єктні літерали

+ +

Об'єктні літерали - це список з нуля або більше пар імен властивостей та асоційованих з ними значень об'єкта, взятих у фігурні дужки  ({}).

+ +
+

Не використовуйте об'єктні літерали на початку інструкції! Це призведе до помилки (або не поводитиметься так, як ви очікували), оскільки { буде інтерпретуватися як початок блоку.

+
+ +

Нижче наведений приклад об’єктного літералу. Перший елемент об'єкта car (автомобіль) визначає властивість myCar та присвоює йому новий рядок "Saturn"; другому елементу, властивості getCar, негайно присвоюється результат виклику функції (carTypes("Honda")); третій елемент, властивість special, використовує існуючу змінну (sales).

+ +
var sales = 'Toyota';
+
+function carTypes(name) {
+  if (name === 'Honda') {
+    return name;
+  } else {
+    return "Вибачте, ми не продаємо автомобілі " + name + ".";
+  }
+}
+
+var car = { myCar: 'Saturn', getCar: carTypes('Honda'), special: sales };
+
+console.log(car.myCar);   // Saturn
+console.log(car.getCar);  // Honda
+console.log(car.special); // Toyota 
+ +

Крім того, ви можете використовувати числовий або рядковий літерал в якості імені властивості, чи вкладати один об'єкт у інший. У наступному прикладі використовуються ці можливості.

+ +
var car = { manyCars: {a: 'Saab', b: 'Jeep'}, 7: 'Mazda' };
+
+console.log(car.manyCars.b); // Jeep
+console.log(car[7]); // Mazda
+ +

Іменем властивості об'єкта може бути будь-який рядок, в тому числі порожній. Якщо ім'я властивості не є дозволеним ідентифікатором JavaScript або числом, воно має бути записане в лапках.

+ +

До імен властивостей, які не є дозволеними ідентифікаторами, не можна звертатись через крапку (.), але можна звертатись та присвоювати значення за допомогою подібної до масиву нотації ("[]").

+ +
var unusualPropertyNames = {
+  '': 'Порожній рядок',
+  '!': 'Бум!'
+}
+console.log(unusualPropertyNames.'');   // SyntaxError: Unexpected string
+console.log(unusualPropertyNames['']);  // Порожній рядок
+console.log(unusualPropertyNames.!);    // SyntaxError: Unexpected token !
+console.log(unusualPropertyNames['!']); // Бум!
+ +

Покращені об'єктні літерали

+ +

У ES2015 об'єктні літерали розширюються для підтримки встановлення прототипу при конструюванні, скороченого запису присвоєнь типу foo: foo, визначення методів, здійснення викликів super та обчислення імен властивостей з виразами.

+ +

Разом вони також зближують об'єктні літерали та оголошення класів (class) і дозволяють об'єктно-орієнтованому дизайну користуватися деякими з тих самих зручностей.

+ +
var obj = {
+    // __proto__
+    __proto__: theProtoObj,
+    // Скорочений запис для ‘handler: handler’
+    handler,
+    // Методи
+    toString() {
+     // Виклики super
+     return 'd ' + super.toString();
+    },
+    // Обчислювані (динамічні) імена властивостей
+    [ 'prop_' + (() => 42)() ]: 42
+};
+ +

Літерали регулярних виразів (RegExp)

+ +

Літерал регулярного виразу (який докладно визначається пізніше) - це шаблон, записаний між слешами. Нижче наведено приклад літерала регулярного виразу:

+ +
var re = /ab+c/;
+ +

Рядкові літерали

+ +

Рядковий літерал - це нуль або більше символів всередині подвійних (") або одинарних (') лапок. Рядок повинен бути позначений лапками одного типу (тобто, або двома одинарними лапками, або двома подвійними лапками).

+ +

Нижче наведено приклади рядкових літералів:

+ +
'раз'
+"два"
+'1234'
+'один рядок \n другий рядок'
+"Мар'яна має кота"
+ +

Ви можете викликати будь-який з методів об'єкта {{jsxref("String")}} на рядковому літералі. JavaScript автоматично перетворює рядковий літерал на тимчасовий об'єкт String, викликає метод, а потім прибирає тимчасовий об'єкт String. Ви також можете використовувати властивість String.length з рядковим літералом:

+ +
// Надрукує кількість символів у рядку, враховуючи пробіли.
+console.log("Мар'яна має кота".length)  // В цьому випадку, 16.
+ +

У ES2015 також доступні шаблонні літерали. Шаблонні літерали пишуться у зворотніх лапках  (`) (гравіс) замість одинарних або подвйних лапок.

+ +

Шаблонні рядки надають синтаксичний цукор для конструювання рядків. (Це схоже на функції інтерполяції рядків у Perl, Python та інших).

+ +

За бажанням може бути додано тег, що дозволить налаштовувати побудову рядка, уникаючи атак типу впровадження або конструюючи структури даних більш високого рівня з вмісту рядка.

+ +
// Створення базового рядкового літералу
+`У JavaScript '\n' - це символ переводу рядка.`
+
+// Багаторядковий запис
+`У JavaScript шаблонні рядки можуть бути записані
+у кількох рядках, а текст в одинарних
+чи подвійних лапках не може.`
+
+// Інтерполяція рядків
+var name = 'Боб', time = 'сьогодні';
+`Привіт, ${name}, як ти ${time}?`
+
+// Створення префіксу HTTP-запиту, який інтерпретує заміни та конструювання
+POST`http://foo.org/bar?a=${a}&b=${b}
+     Content-Type: application/json
+     X-Credentials: ${credentials}
+     { "foo": ${foo},
+       "bar": ${bar}}`(myOnReadyStateChangeHandler);
+ +

Вам варто використовувати рядкові літерали, якщо немає потреби використовувати конкретно об'єкт String. Дивіться {{jsxref("String")}} для більш детальної інформації про об'єкти String.

+ +

Використання спеціальних символів у рядках

+ +

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

+ +
'один рядок \n другий рядок'
+ +

Наступна таблиця наводить спеціальні символи, які можна використовувати у рядках JavaScript.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Таблиця: спеціальні символи JavaScript
СимволЗначення
\0Нуль-символ
\bПовернення на крок
\fЗміна сторінки
\nНовий рядок
\rПовернення каретки
\tГоризонтальна табуляція
\vВертикальна табуляція
\'Апостроф або одинарні лапки
\"Подвійні лапки
\\Зворотній слеш
\XXXСимвол у кодуванні Latin-1, який містить до трьох цифр у вісімковій системі числення XXX між 0 та 377. Наприклад, \251 - це вісімкова послідовність для знаку охорони авторського права.
\xXXСимвол у кодуванні Latin-1, вказаний двома цифрами у шістнадцятковій системі числення XX між 00 та FF. Наприклад, \xA9 - це шістнадцяткова послідовність  для знаку охорони авторського права.
\uXXXXСимвол Юнікоду, вказаний чотирма цифрами у шістнадцятковій системі числення XXXX. Наприклад, \u00A9 - це Юнікодова послідовність для знаку охорони авторського права. Дивіться екрановані послідовності Юнікоду.
\u{XXXXX}Екранування кодів символів Юнікоду. Наприклад, \u{2F804} - це те саме, що й прості екранування Юнікоду \uD87E\uDC04.
+ +

Екранування символів

+ +

Для символів, не перелічених у таблиці, зворотній слеш перед символом ігнорується, але таке використання не рекомендоване, і його слід уникати.

+ +

Ви можете вставити лапки у рядок, поcтавивши перед ними зворотній слеш. Це називається екрануванням лапок. Наприклад:

+ +
var quote = "Він читав \"Кремацію Сема Маꥳ\" Р.Дж. Сервіса.";
+console.log(quote);
+ +

Результатом цього буде:

+ +
Він читав "Кремацію Сема Маꥳ" Р.Дж. Сервіса.
+ +

Щоб включити у рядок сам зворотний слеш, ви маєте його екранувати. Наприклад, щоб присвоїти рядкові шлях до файлу c:\temp, використовуйте наступне:

+ +
var home = 'c:\\temp';
+ +

Ви також можете екранувати розрив рядка, поставивши перед ним зворотній слеш. І зворотній слеш, і розрив рядка видаляються зі значення рядка.

+ +
var str = 'цей текст \
+розбито \
+на кілька \
+рядків.'
+console.log(str);   // цей текст розбито на кілька рядків.
+ +

Хоча у JavaScript немає синтаксису "heredoc", ви можете наблизитися до нього, додавши в кінці кожного рядка екранування розриву рядка та екранування символа нового рядка:

+ +
var poem =
+'Roses are red,\n\
+Violets are blue.\n\
+Sugar is sweet,\n\
+and so is foo.'
+ +

ECMAScript 2015 вводить новий тип літералів, а саме шаблонні літерали. Це додає багато нових функцій, в тому числі багаторядковий запис!

+ +
var poem =
+`Roses are red,
+Violets are blue.
+Sugar is sweet,
+and so is foo.` 
+ +

Більше інформації

+ +

Цей розділ фокусується на базовому синтаксисі оголошень та типів. Щоб дізнатися більше про мовні конструкції JavaScript, дивіться також наступні розділи цього посібника:

+ + + +

У наступному розділі ми розглянемо конструкції потоку керування та обробку помилок.

+ +

{{PreviousNext("Web/JavaScript/Guide/Introduction", "Web/JavaScript/Guide/Control_flow_and_error_handling")}}

diff --git a/files/uk/web/javascript/guide/index.html b/files/uk/web/javascript/guide/index.html new file mode 100644 index 0000000000..868d0b7864 --- /dev/null +++ b/files/uk/web/javascript/guide/index.html @@ -0,0 +1,131 @@ +--- +title: Посібник JavaScript +slug: Web/JavaScript/Guide +tags: + - Guide + - JavaScript + - 'l10n:priority' + - Посібник +translation_of: Web/JavaScript/Guide +--- +
{{jsSidebar("JavaScript Guide")}}
+ +

Посібник з JavaScript показує, як використовувати мову JavaScript, і надає її попередній огляд. Та якщо ви шукаєте детальну інформацію щодо особливостей мови, зазирніть у Довідник з JavaScript.

+ +

Розділи

+ +

Цей посібник поділено на декілька розділів:

+ + + + + + + + + +

{{Next("Web/JavaScript/Guide/Introduction")}}

diff --git a/files/uk/web/javascript/guide/indexed_collections/index.html b/files/uk/web/javascript/guide/indexed_collections/index.html new file mode 100644 index 0000000000..0c4dfaef25 --- /dev/null +++ b/files/uk/web/javascript/guide/indexed_collections/index.html @@ -0,0 +1,578 @@ +--- +title: Indexed collections +slug: Web/JavaScript/Guide/Indexed_collections +translation_of: Web/JavaScript/Guide/Indexed_collections +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}
+ +

У цьому розділ представлено набір даних, упорядкованих за значенням індексу. Це включає масиви та подібні до масиву конструкції, такі як об'єкти {{jsxref("Array")}} та {{jsxref("TypedArray")}} .

+ +

Об'єкт Array

+ +

Масив - це упорядкований набір значень, на який ви посилаєтесь з ім'ям та індексом.

+ +

Наприклад, розглянемо масив під назвою emp, який містить імена працівників, індексовані їх числовим номером співробітника. Так emp[1] буде працівником номер один, emp[2] працівником номером два, тощо.

+ +

У JavaScript немає явного типу даних масиву. Однак ви можете використовувати заздалегідь заданий об’єкт Array та його методи для роботи з масивами у ваших програмах. Об'єкт Array має методи маніпулювання масивами різними способами, такими як з'єднання(joining), реверсування(reversing) та сортування. Він має властивість визначати довжину масиву та інші властивості для використання з регулярними виразами.

+ +

Створення масиву

+ +

Наступні операції створюють еквівалентні масиви:

+ +
let arr = new Array(element0, element1, ..., elementN)
+let arr = Array(element0, element1, ..., elementN)
+let arr = [element0, element1, ..., elementN]
+
+ +

element0, element1, ..., elementN - це список значень елементів масиву. Коли ці значення задані, масив ініціалізується з ними як елементами масиву. Властивість довжина (length) масиву встановлюється рівною кількості аргументів.

+ +

Синтаксис дужки називається "літералом масиву" або "ініціалізатором масиву". Він коротший, ніж інші форми створення масиву, і тому загалом кращий. Докладніше див. Літерали масиву.

+ +

Для створення масиву з ненульовою довжиною, але без будь-яких елементів, може бути використане будь-яке з наведеного нижче:

+ +
// This...
+let arr = new Array(arrayLength)
+
+// ...буде такий саме масив як цей
+let arr = Array(arrayLength)
+
+// Це має точно такий же ефект
+let arr = []
+arr.length = arrayLength
+
+ +
+

Примітка: У наведеному вище коді, arrayLength повинен бути типу Number. У іншому випадку, буде створений масив з єдиним елементом (з наданим значенням). Виклик arr.length поверне arrayLength, але масив у дійсності убде містити порожні (undefined) елементи. Запуск циклу {{jsxref("Statements/for...in","for...in")}} для масиву не поверне жодного з елементів масиву.

+
+ +

Крім нещодавно означеної змінної, як показано вище, масиви також можуть бути призначені як властивість для нового або існуючого об'єкта:

+ +
let obj = {}
+// ...
+obj.prop = [element0, element1, ..., elementN]
+
+// або
+let obj = {prop: [element0, element1, ...., elementN]}
+
+ +

Якщо Ви хочете ініціалізувати масив з єдиним елементом, а цей елемент є Number, ви повинні використовувати синтаксис квадратних дужок. Коли одне значення Number передається конструктору або функції Array(), воно інтерпретується як arrayLength, а не як окремий елемент.

+ +
let arr = [42]       // Створює масив тільки з одним елементом:
+                     // числом 42.
+
+let arr = Array(42)  // Створює масив без жодного елементу
+                     // і довжина масиву arr.length встановлена в 42.
+                     //
+                     // Це еквівалентно наступному:
+let arr = []
+arr.length = 42
+
+ +

Виклик Array(N) призводить до RangeError, якщо N - це не ціле число, тобто дробова частина якого не дорівнює нулю. Наступний приклад ілюструє таку поведінку.

+ +
let arr = Array(9.3)   // RangeError: Invalid array length
+
+ +

Якщо ваш код потребує створення масивів з окремими елементами довільного типу даних, безпечніше використовувати літерали масиву. Крім того, спершу створіть порожній масив, перш ніж додати до нього один елемент.

+ +

У ES2015 ви можете використовувати статичний метод {{jsxref("Array.of")}} для створення масивів з одним елементом.

+ +
let wisenArray = Array.of(9.3)   // wisenArray містить тільки один елемент 9.3
+ +

Заповнення масиву

+ +

Ви можете заповнити масив, призначивши значення його елементам. Наприклад:

+ +
let emp = []
+emp[0] = 'Casey Jones'
+emp[1] = 'Phil Lesh'
+emp[2] = 'August West'
+
+ +
+

Примітка: Якщо ви подасте неціле значення для оператора масиву в наведеному вище коді, буде створено властивість в об'єкті, що представляє масив, замість елемента масиву.

+ +
let arr = []
+arr[3.4] = 'Oranges'
+console.log(arr.length)                 // 0
+console.log(arr.hasOwnProperty(3.4))    // true
+
+
+ +

Ви також можете заповнити масив під час його створення:

+ +
let myArray = new Array('Hello', myVar, 3.14159)
+// або
+let myArray = ['Mango', 'Apple', 'Orange']
+
+ +

Звернення до елементів масиву

+ +

Ви звертаєтеся на елементи масиву, використовуючи порядковий номер елемента. Наприклад, припустимо, Ви означуєте такий масив:

+ +
let myArray = ['Wind', 'Rain', 'Fire']
+
+ +

Потім Ви звертаєтеся до першого елементу масиву як до myArray[0], а до другого елементу масиву як до myArray[1]. Індекс елементів починається з нуля.

+ +
+

Примітка: Оператор масиву (квадратні дужки) також використовуються для доступу до властивостей масиву. (Масиви також є об'єктами в JavaScript). Наприклад:

+ +
let arr = ['one', 'two', 'three']
+arr[2]          // three
+arr['length']   // 3
+
+
+ +

Довжина масиву

+ +

На рівні реалізації масиви JavaScript фактично зберігають свої елементи як стандартні властивості об'єкта, використовуючи індекс масиву як ім'я властивості.

+ +

Властивість length особлива. Вона завжди повертає індекс останнього елемента плюс один. (У наведеному нижче прикладі 'Dusty' індексується на рівні 30, тому cats.length повертає 30 + 1).

+ +

Пам'ятайте, що індекси масиву JavaScript базуються на 0: вони починаються з 0, а не 1. Це означає, що властивість length буде на один більше, ніж найвищий індекс, що зберігається в масиві:

+ +
let cats = []
+cats[30] = ['Dusty']
+console.log(cats.length) // 31
+
+ +

Ви також можете записати значення у властивість length .

+ +

Введення значення, коротшого за кількість збережених елементів, скорочує масив. Написання 0 спустошує масив повністю:

+ +
let cats = ['Dusty', 'Misty', 'Twiggy']
+console.log(cats.length)  // 3
+
+cats.length = 2
+console.log(cats)  // logs "Dusty, Misty" - Twiggy видалено
+
+cats.length = 0
+console.log(cats)  // logs []; масив cats array - порожній
+
+cats.length = 3
+console.log(cats)  // logs [ <3 пустих елементи> ]
+
+ +

Ітерація з масивами

+ +

Поширена операція - це перебір значень масиву, з обробкою кожного елементу. Найпростіший спосіб зробити це наступним чином:

+ +
let colors = ['red', 'green', 'blue']
+for (let i = 0; i < colors.length; i++) {
+  console.log(colors[i])
+}
+
+ +

Якщо ви знаєте, що жоден з елементів вашого масиву не повертає false в булевому контексті, наприклад, якщо ваш масив складається з вузлів DOM, Ви можете використовувати більш ефективну ідіому:

+ +
let divs = document.getElementsByTagName('div')
+for (let i = 0, div; div = divs[i]; i++) {
+  /* Process div in some way */
+}
+
+ +

Це дозволяє уникнути накладних перевірок довжини масиву та гарантує, що змінна div для додаткової зручності переназначається поточному елементу на кожній ітерації .

+ +

Метод  {{jsxref("Array.forEach", "forEach()")}} забезпечує інший спосіб ітерації з масивом:

+ +
let colors = ['red', 'green', 'blue']
+colors.forEach(function(color) {
+  console.log(color)
+})
+// red
+// green
+// blue
+
+ +

Крім того, ви можете скоротити код для параметра forEach за допомогою функції стрілок ES2015:

+ +
let colors = ['red', 'green', 'blue']
+colors.forEach(color => console.log(color))
+// red
+// green
+// blue
+
+ +

Функція, передана forEach , виконується один раз для кожного елемента масиву, при цьому елемент масиву передається як аргумент функції. Не присвоєні значення не перебираються в циклі forEach.

+ +

Зауважте, що елементи масиву, опущені при означенні масиву, не перебираються під час ітерації forEach, але пеербираються, коли вручну елемнту було присвоєно undefined:

+ +
let array = ['first', 'second', , 'fourth']
+
+array.forEach(function(element) {
+  console.log(element)
+})
+// first
+// second
+// fourth
+
+if (array[2] === undefined) {
+  console.log('array[2] is undefined')  // true
+}
+
+array = ['first', 'second', undefined, 'fourth']
+
+array.forEach(function(element) {
+  console.log(element)
+})
+// first
+// second
+// undefined
+// fourth
+
+ +

Оскільки елементи JavaScript зберігаються як стандартні властивості об'єкта, не рекомендується проводити повторення через масиви JavaScript, використовуючи цикли {{jsxref("Statements/for...in","for...in")}} , оскільки будуть перебрані як нормальні елементи так і всі властивості масиву.

+ +

Методи масивів

+ +

Об'єкт {{jsxref("Array")}} має наступні методи:

+ +

{{jsxref("Array.concat", "concat()")}} з'єднує два або більше масива і повертає новий масив.

+ +
let myArray = new Array('1', '2', '3')
+myArray = myArray.concat('a', 'b', 'c')
+// myArray тепер такий ["1", "2", "3", "a", "b", "c"]
+
+ +

{{jsxref("Array.join", "join(delimiter = ',')")}} об'єднує всі елементи масиву в рядок.

+ +
let myArray = new Array('Wind', 'Rain', 'Fire')
+let list = myArray.join(' - ') // list є "Wind - Rain - Fire"
+
+ +

{{jsxref("Array.push", "push()")}} додає один або більше елементів в кінець масиву і повертає отриману довжину length масиву.

+ +
let myArray = new Array('1', '2')
+myArray.push('3')  // myArray тепер ["1", "2", "3"]
+
+ +

{{jsxref("Array.pop", "pop()")}} видаляє останній елемент з масиву і повертає цей елемент.

+ +
let myArray = new Array('1', '2', '3')
+let last = myArray.pop()
+// myArray тепер ["1", "2"], last = "3"
+
+ +

{{jsxref("Array.shift", "shift()")}} видаляє перший елемент з масиву і повертає цей елемент.

+ +
let myArray = new Array('1', '2', '3')
+let first = myArray.shift()
+// myArray тепер ["2", "3"], first є "1"
+
+ +

{{jsxref("Array.unshift", "unshift()")}}  додає один або більше елементів до передньої частини масиву і повертає нову довжину масиву.

+ +
let myArray = new Array('1', '2', '3')
+myArray.unshift('4', '5')
+// myArray став ["4", "5", "1", "2", "3"]
+
+ +

{{jsxref("Array.slice", "slice(start_index, upto_index)")}} виймає частину масиву і повертає новий масив.

+ +
let myArray = new Array('a', 'b', 'c', 'd', 'e')
+myArray = myArray.slice(1, 4)  // починаючи з 1-го вимйає елементи до 4-го
+                               // повертає [ "b", "c", "d"]
+
+ +

{{jsxref("Array.splice", "splice(index, count_to_remove, addElement1, addElement2, ...)")}}  видаляє елементи з масиву та (необов'язково) замінює їх. Він повертає елементи, вилучені з масиву.

+ +
let myArray = new Array('1', '2', '3', '4', '5')
+myArray.splice(1, 3, 'a', 'b', 'c', 'd')
+// myArray тепер ["1", "a", "b", "c", "d", "5"]
+// Цей код стартує з першого індексу (or where the "2" was),
+// видаляє 3 елементи, а тоді вставляє всі підряд
+// на це місце.
+
+ +

{{jsxref("Array.reverse", "reverse()")}} транспонує масив: перший елемент масиву стає останнім, а останній стає першим. Він повертає посилання на масив.

+ +
let myArray = new Array('1', '2', '3')
+myArray.reverse()
+// транспонований масив myArray = ["3", "2", "1"]
+
+ +

{{jsxref("Array.sort", "sort()")}} сортує елементи масиву на місці та повертає посилання на масив.

+ +
let myArray = new Array('Wind', 'Rain', 'Fire')
+myArray.sort()
+// відсортований масив myArray = ["Fire", "Rain", "Wind"]
+
+ +

sort() також може скористатися функцією зворотного виклику для визначення порівняння елементів масиву.

+ +

Метод sort (та інші нижче), які приймають функцію зворотного виклику, відомі як ітераційні методи, оскільки певним чином вони перебирають весь масив. Кожен з них бере необов'язковий другий аргумент під назвою thisObject. Якщо  thisObject передається, він стає значенням ключового слова this всередині тіла функції зворотного виклику. Якщо це не передбачено, як і в інших випадках, коли функція викликається поза явним контекстом об'єкта, this стосуватиметься глобального об'єкта (window) при використанні функції вказівника зворотного виклику, або undefined при використанні нормальної функції зворотного виклику.

+ +

Функція зворотного виклику викликається двома аргументами, які є елементами масиву.

+ +

Функція нижче порівнює два значення і повертає одне з трьох значень:

+ +

Наприклад, наступне буде сортувати за останньою літерою рядка:

+ +
let sortFn = function(a, b) {
+  if (a[a.length - 1] < b[b.length - 1]) return -1;
+  if (a[a.length - 1] > b[b.length - 1]) return 1;
+  if (a[a.length - 1] == b[b.length - 1]) return 0;
+}
+myArray.sort(sortFn)
+// відсортований масив myArray = ["Wind","Fire","Rain"]
+ + + +

{{jsxref("Array.indexOf", "indexOf(searchElement[, fromIndex])")}} шукає масив для searchElement та повертає індекс першого збігу.

+ +
let a = ['a', 'b', 'a', 'b', 'a']
+console.log(a.indexOf('b'))     // пише 1
+
+// Тепер спробуйте ще раз, починаючи з останнього співпадіння
+console.log(a.indexOf('b', 2))  // пише 3
+console.log(a.indexOf('z'))     // пише -1, оскільки 'z' не було знайдено
+
+ +

{{jsxref("Array.lastIndexOf", "lastIndexOf(searchElement[, fromIndex])")}} працює як indexOf, але починає з кінця і шукає у зворотному порядку.

+ +
let a = ['a', 'b', 'c', 'd', 'a', 'b']
+console.log(a.lastIndexOf('b'))     // пише 5
+
+// Тепер спробуйте ще раз, починаючи з останнього співпадіння
+console.log(a.lastIndexOf('b', 4))  // пише 1
+console.log(a.lastIndexOf('z'))     // пише -1
+
+ +

{{jsxref("Array.forEach", "forEach(callback[, thisObject])")}} виконує callback на кожному елементі масиву і повертає undefined.

+ +
let a = ['a', 'b', 'c']
+a.forEach(function(element) { console.log(element) })
+// logs each item in turn
+
+ +

{{jsxref("Array.map", "map(callback[, thisObject])")}} повертає новий масив повернутого значення при виконанні зворотного виклику callback на кожному елементі масиву.

+ +
let a1 = ['a', 'b', 'c']
+let a2 = a1.map(function(item) { return item.toUpperCase() })
+console.log(a2) // logs ['A', 'B', 'C']
+
+ +

{{jsxref("Array.filter", "filter(callback[, thisObject])")}} повертає новий масив, що містить елементи, для яких callback повернув true.

+ +
let a1 = ['a', 10, 'b', 20, 'c', 30]
+let a2 = a1.filter(function(item) { return typeof item === 'number'; })
+console.log(a2)  // logs [10, 20, 30]
+
+ +

{{jsxref("Array.every", "every(callback[, thisObject])")}} повертає true, якщо callback повертає true для кожного елемента масиву.

+ +
function isNumber(value) {
+  return typeof value === 'number'
+}
+let a1 = [1, 2, 3]
+console.log(a1.every(isNumber))  // logs true
+let a2 = [1, '2', 3]
+console.log(a2.every(isNumber))  // logs false
+
+ +

{{jsxref("Array.some", "some(callback[, thisObject])")}} повертає true , якщо callback повертає true для принаймні одного елемента в масиві.

+ +
function isNumber(value) {
+  return typeof value === 'number'
+}
+let a1 = [1, 2, 3]
+console.log(a1.some(isNumber))  // logs true
+let a2 = [1, '2', 3]
+console.log(a2.some(isNumber))  // logs true
+let a3 = ['1', '2', '3']
+console.log(a3.some(isNumber))  // logs false
+
+ +

{{jsxref("Array.reduce", "reduce(callback[, initialValue])")}}  застосовує callback(accumulator, currentValue[, currentIndex[, array]]) для кожного значення масиву з метою зменшення списку елементів до одного значення. Функція зменшення повертає кінцеве значення, повернене функцією callback .

+ +

Якщо вказано initialValue , тоді callback викликається initialValue як значення першого параметра, а значення першого елемента в масиві - як значення другого параметра.

+ +

Якщо initialValue не вказана, першими двома параметрами callback будуть перший і другий елементи масиву. При кожному наступному виклику значенням першого параметра буде будь-який callback , повернутий при попередньому виклику, а значення другого параметра буде наступним значенням масиву.

+ +

Якщо для callback  потрібен доступ до індексу оброблюваного елемента, для доступу до всього масиву вони доступні як необов'язкові параметри.

+ +
let a = [10, 20, 30]
+let total = a.reduce(function(accumulator, currentValue) { return accumulator + currentValue }, 0)
+console.log(total) // Prints 60
+
+ +

{{jsxref("Array.reduceRight", "reduceRight(callback[, initialValue])")}} працює подібно  reduce(), але починається з останнього елемента.

+ +

reduce та reduceRight - найменш очевидний із ітеративних методів масиву. Їх слід використовувати для алгоритмів, що поєднують два значення рекурсивно, щоб зменшити послідовність до одного значення.

+ +

Багатовимірні масиви

+ +

Масиви можуть бути вкладені, тобто масив може містити інший масив як елемент. Використовуючи цю характеристику масивів JavaScript, можна створити багатовимірні масиви.

+ +

Наступний код створює багатовимірний масив.

+ +
let a = new Array(4)
+for (let i = 0; i < 4; i++) {
+  a[i] = new Array(4)
+  for (let j = 0; j < 4; j++) {
+    a[i][j] = '[' + i + ', ' + j + ']'
+  }
+}
+
+ +

Цей приклад створює масив із таких рядків:

+ +
Row 0: [0, 0] [0, 1] [0, 2] [0, 3]
+Row 1: [1, 0] [1, 1] [1, 2] [1, 3]
+Row 2: [2, 0] [2, 1] [2, 2] [2, 3]
+Row 3: [3, 0] [3, 1] [3, 2] [3, 3]
+
+ +

Масиви та регулярні вирази

+ +

Коли масив є результатом збігу між регулярним виразом і рядком, масив повертає властивості та елементи, які надають інформацію про збіг. Масив - це повернене значення {{jsxref("Global_Objects/RegExp/exec","RegExp.exec()")}}, {{jsxref("Global_Objects/String/match","String.match()")}}, і {{jsxref("Global_Objects/String/split","String.split()")}}. Інформацію про використання масивів з регулярними виразами див Regular Expressions.

+ +

Робота з масиво-подібними об'єктами

+ +

Деякі об`єкти JavaScript, такі як NodeList повертають  document.getElementsByTagName() або об'єкт {{jsxref("Functions/arguments","arguments")}}, доступний в тілі функції, який виглядає і поводиться як масиви на поверхні, але не ділиться всіма їх методами. Наприклад, об'єкт arguments забезпечує атрибут {{jsxref("Global_Objects/Function/length","length")}} але не реалізує метод {{jsxref("Array.forEach", "forEach()")}}.

+ +

Методи прототипу масиву можна викликати для інших об’єктів, подібних до масиву. наприклад:

+ +
function printArguments() {
+  Array.prototype.forEach.call(arguments, function(item) {
+    console.log(item)
+  })
+}
+
+ +

Методи прототипу масиву також можна використовувати і для рядків, оскільки вони забезпечують послідовний доступ до своїх символів аналогічно масивам:

+ +
Array.prototype.forEach.call('a string', function(chr) {
+  console.log(chr)
+})
+
+ +

Типізовані масиви

+ +

JavaScript typed arrays є схожими на масив об'єктів і забезпечують механізм доступу до необроблених бінарних даних. Як ви вже знаєте, об'єкт {{jsxref("Array")}} динамічно росте і скорочується і може мати будь-яке значення JavaScript. Рушії JavaScript виконують оптимізацію, щоб ці масиви були швидкими. Однак, оскільки веб-застосунки стають все більш потужними, додаючи такі функції, як маніпулювання аудіо та відео, доступ до необроблених даних за допомогою WebSockets тощо, стало зрозуміло, що є випадки, коли корисним буде код JavaScript для швидкого та легкого маніпулювати необробленими бінарними даними в типізованих масивах.

+ +

Буфери та представлення: типізовані архітектури масивів

+ +

Щоб досягти максимальної гнучкості та ефективності, JavaScript типізовані масиви розділили реалізацію на буфери (buffers) та представлення(views). Буфер (реалізований об'єктом {{jsxref ("ArrayBuffer")}}) - це об'єкт, що представляє фрагмент даних; він не має формату, про який можна говорити, і не пропонує механізму доступу до його вмісту. Для доступу до пам'яті, що міститься в буфері, вам потрібно скористатися представленням. Представлення забезпечує контекст - тобто тип даних, початкове зміщення та кількість елементів - який перетворює дані у фактично набраний масив.

+ +

Typed arrays in an ArrayBuffer

+ +

ArrayBuffer

+ +

{{jsxref("ArrayBuffer")}} - це тип даних, який використовується для репрезентації загального буфера даних бінарних даних фіксованої довжини. Ви не можете безпосередньо маніпулювати вмістом ArrayBuffer; натомість ви створюєте типізоване представлення масиву або {{jsxref("DataView")}} який представляє буфер у певному форматі, і використовують його для читання та запису вмісту буфера.

+ +

Типізоване представлення масиву

+ +

Типізовані представлення масивів мають самостійно описові назви та надають представлення для всіх звичайних числових типів, таких як  Int8, Uint32, Float64 і так далі. Існує один спеціальний вид типізованого представлення масиву Uint8ClampedArray. Він фіксує значення між 0 та 255.  Це корисно, наприклад, для обробки даних Canvas.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeValue RangeSize in bytesDescriptionWeb IDL typeEquivalent C type
{{jsxref("Int8Array")}}-128 to 12718-bit two's complement signed integerbyteint8_t
{{jsxref("Uint8Array")}}0 to 25518-bit unsigned integeroctetuint8_t
{{jsxref("Uint8ClampedArray")}}0 to 25518-bit unsigned integer (clamped)octetuint8_t
{{jsxref("Int16Array")}}-32768 to 32767216-bit two's complement signed integershortint16_t
{{jsxref("Uint16Array")}}0 to 65535216-bit unsigned integerunsigned shortuint16_t
{{jsxref("Int32Array")}}-2147483648 to 2147483647432-bit two's complement signed integerlongint32_t
{{jsxref("Uint32Array")}}0 to 4294967295432-bit unsigned integerunsigned longuint32_t
{{jsxref("Float32Array")}}1.2×10-38 to 3.4×1038432-bit IEEE floating point number (7 significant digits e.g., 1.1234567)unrestricted floatfloat
{{jsxref("Float64Array")}}5.0×10-324 to 1.8×10308864-bit IEEE floating point number (16 significant digits e.g., 1.123...15)unrestricted doubledouble
{{jsxref("BigInt64Array")}}-263 to 263-1864-bit two's complement signed integerbigintint64_t (signed long long)
{{jsxref("BigUint64Array")}}0 to 264-1864-bit unsigned integerbigintuint64_t (unsigned long long)
+ +

For more information, see JavaScript typed arrays and the reference documentation for the different {{jsxref("TypedArray")}} objects.

+ +

{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Keyed_Collections")}}

diff --git a/files/uk/web/javascript/guide/introduction/index.html b/files/uk/web/javascript/guide/introduction/index.html new file mode 100644 index 0000000000..8f1d97d352 --- /dev/null +++ b/files/uk/web/javascript/guide/introduction/index.html @@ -0,0 +1,147 @@ +--- +title: Вступ +slug: Web/JavaScript/Guide/Introduction +tags: + - JavaScript + - Вступ + - Початківець + - Путівник +translation_of: Web/JavaScript/Guide/Introduction +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}
+ +

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

+ +

Необхідний рівень підготовки

+ +

Цей навчальний посібник передбачає, що ви маєте деякі початкові знання:

+ + + +

Де знайти інформацію з JavaScript

+ +

Документація з JavaScript на ресурсі MDN містить таке:

+ + + +

Якщо ви новачок у JavaScript, почніть із вивчення статей, розміщених у навчальній секції (learning area) та Посібника з JavaScript. Опанувавши основи, можете використовувати Довідник з JavaScript для отримання більш детальної інформації про конкретні об'єкти та вирази (конструкції мови).

+ +

Що таке JavaScript?

+ +

JavaScript — кроссплатформна об'єктно-зорієнтована мова сценаріїв (скриптів). Рушій JavaScript підключається до об'єктів свого середовища виконання (зазвичай, веб-переглядача) та надає можливість керування ними.

+ +

Мова JavaScript має стандартну бібліотеку об'єктів (таких як Array, Date та Math) і основний набір елементів мови програмування, таких як оператори, керівні структури та вирази.

+ +

Ядро JavaScript може бути розширене для різних потреб шляхом доповнення його додатковими об'єктами. Наприклад:

+ + + +

JavaScript та Java

+ +

Мови програмування JavaScript та Java у окремих рисах схожі між собою, але все одно докорінно відрізняються одна від одної. Мова JavaScript чимось нагадує Java, але, на відміну від останньої, не має чіткої типізації даних та строгого контролю за типами.

+ +

JavaScript наслідує синтаксис більшості виразів Java, також наслідуються угоди про іменування та основні конструкції керування перебігом виконання сценарію. Це і стало причиною того, що свого часу назву мови змінили з LiveScript на JavаScript.

+ +

На відміну від системи часу коміляції декларативно побудованих класів у Java, мова JavaScript підтримує систему часу виконання, що ґрунтується на невеликій кількості типів даних, представлених числовим типом, логічними, та рядковими значеннями. JavaScript має об'єктну модель, що спирається на прототипи, замість більш поширеної, побудованої на класах, об'єктної моделі, властивої мові Java. Модель на базі прототипів надає можливість динамічного спадкування; тобто успадковане може бути різним для різних об'єктів. Також у JavaScript реалізована підтримка функцій без будь-яких особливих декларативних вимог. Функції можуть бути властивостями об'єктів, функціями, що виконуються, та слабко типізованими методами.

+ +

Для JavaScript властива вільніша форма мови, ніж для Java. Вас не зобов'язують оголошувати всі змінні, класи та методи. JavaScript-програміста не турбує питання, є метод відкритим (public), закритим (private), чи захищеним (protected). Для змінних, параметрів, та типів, що повертаються функціями, не вказується явним чином їх тип.

+ +

Java — це мова програмування, яка базується на класах, розроблена для швидкого виконання та забезпечення захищеності типів. Захищеність типів означає, що не можна, наприклад, привести тип integer до типу object reference, або отримати доступ до закритої пам'яті, маніпулюючи з байткодом Java. Базована на класах об'єктна модель означає, що програма повністю складається із класів та їх методів. Успадкування класів у Java та строга типізація взагалі вимагають існування тісно пов'язаних між собою ієрархій об'єктів. Ці вимоги роблять програмування на Java більш складним, ніж JavaScript-програмування.

+ +

На противагу цьому, JavaScript, за своїм духом, близька до невеликих мов із динамічною типізацією, таких, як HyperTalk та dBASE. Ці скриптові мови надають інструменти програмування для більш широкого загалу користувачів, завдяки простоті синтаксису, вбудованим функціональним можливостям зі спеціалізації, та мінімальним вимогам до створення об'єктів.

+ + + + + + + + + + + + + + + + + + + + + + + +
JavaScript у порівнянні з Java
Мова JavaScriptМова Java
+

Об'єктно орієнтована. Не має відмінностей між типами об'єктів. Спадкування здійснюється через механізм прототипів, а властивості та методи можуть бути динамічно додані до будь-якого об'єкту.

+
+

Базується на класах. Об'єкти поділяються на класи та екземпляри. Спадкування реалізоване через ієрархію класів. До класів та екземплярів не можна динамічно додавати властивості та методи.

+
Для змінних не декларуються типи даних (динамічна типізація).Для змінних необхідне декларування типів даних (статична типізація)
Не може автоматично вести запис до жорсткого диску.Може автоматично вести запис до жорсткого диску.
+ +

Щоб отримати більше інформації щодо відмінностей між JavaScript та Java, відвідайте цей розділ: Докладно про об'єктну модель.

+ +

JavaScript та специфікація ECMAScript

+ +

JavaScript стандартизований Європейською асоціаіцєю з стандартизації інформаційних та комунікаційних систем — Ecma International (спершу складноскорот ECMA позначав European Computer Manufacturers Association). Ця стандартизована версія JavaScript, що має назву ECMAScript, однаково працює у всіх застосунках, що підтримують стандарт. Різні компанії можуть використовувати цей відкритий стандарт для розробки своїх реалізацій JavaScript. ECMAScript стандарт задокументований у специфікації ECMA-262. Див. Нове у JavaScript, щоб довідатись більше про різні версії JavaScript та про редакції специфікації ECMAScript.

+ +

Стандарт ECMA-262 також затверджений ISO (International Organization for Standardization), як ISO-16262. Ви можете знайти специфікацію на сайті Ecma International website. Специфікація ECMAScript не описує об'єктну модель документа Document Object Model (DOM), яка стандартизована World Wide Web Consortium (W3C). DOM визначає спосіб, у який об'єкти HTML-документа стають доступними із вашого скрипта. Для отримання більш повного уявлення про технології, що використовуються при програмуванні на JavaScript, зверніться до статті Огляд технологій JavaScript.

+ +

Документація з JavaScript та специфікація ECMAScript

+ +

Специфікація ECMAScript є низкою вимог до реалізації ECMAScript. Цих вимог слід дотримуватись, щоб запровадити відповідні стандартам можливості мови у реалізації ECMAScript, або, щоб створити рушій (наприклад, SpiderMonkey у Firefox або v8 у Chrome).

+ +

Документ ECMAScript не призначений для того, щоб надавати допомогу у програмуванні скриптів. Для отримання інформації про написання скриптів слід використовувати документацію JavaScript.

+ +

У специфікації ECMAScript використовується термінологія і синтаксис, з якими JavaScript-програмісти можуть бути і не знайомі. Не зважаючи на те, що опис мови у ECMAScript може бути дещо іншим, сама мова залишається такою самою. JavaScript підтримує весь функціонал, закладений у специфікації ECMAScript.

+ +

Документація JavaScript описує аспекти мови, які використовує програміст JavaScript.

+ +

Початок роботи із JavaScript

+ +

Розпочати працювати з JavaScript дуже просто: все, що вам потрібно — сучасний переглядач. У даному посібнику розглядаються деякі можливості JavaScript, які, на даний час, реалізовані лише в останніх версіях Firefox, тому рекомендується використовувати саму останню версію Firefox.

+ +

До Firefox вбудовано два інструменти, що роблять його використання дуже зручним для експериментів із JavaScript: Web Console та Scratchpad.

+ +

Веб-консоль — Web Console

+ +

Web Console надає інформацію про поточну завантажену веб-сторінку, а також містить вбудовану командну стрічку (command line), у якій ви маєте змогу виконувати інструкції JavaScript у поточній сторінці.

+ +

Щоб відкрити Web Console (Ctrl + Shift + K), оберіть пункт "Веб-консоль" із меню "Розробник" у меню Firefox. Вона з'явиться у нижній частині вікна переглядача. Внизу консолі, по всій її довжині, розміщено командну стрічку, до якої ви можете вводити команди та вирази JavaScript. Результати їх виконання одразу з'являться у панелі, що знаходиться вище:

+ +

+ +

Чернетка — Scratchpad

+ +

Веб-консоль чудово підходить для виконання окремих рядків JavaScript, і, хоча, ви й можете вводити й виконувати рядки по одному, це не дуже зручно, і ви не можете зберігати зразки свого коду з використанням Веб-консолі. Таким чином, для виконання більш складних прикладів, є кращий інструмент — Чернетка (Scratchpad).

+ +

Щоб відкрити Scratchpad (Shift + F4), оберіть "Чернетка" ("Scracthpad") у меню "Розробник" із меню Firefox. Він відкривається у окремому вікні і є редактором, який можна використовувати для запису і виконання JavaScript у переглядачі. Ви також можете зберегти скрипти до диску і завантажувати їх з диска.

+ +

+ +

Hello World

+ +

Щоб розпочати роботу з JavaScript, відкрийте Scratchpad та напишіть свою першу програму "Hello world":

+ +
function greetMe(yourName) {
+  alert("Hello " + yourName);
+}
+
+greetMe("World");
+
+ +

Натисніть Ctrl + R, щоб побачити, як цей код буде виконано у переглядачі!

+ +

На наступних сторінках цього посібника буде розглянуто синтаксис та можливості мови JavaScript, що дозволить вам створювати більш складні застосунки.

+ +

{{PreviousNext("Web/JavaScript/Guide", "Web/JavaScript/Guide/Grammar_and_types")}}

diff --git a/files/uk/web/javascript/guide/iterators_and_generators/index.html b/files/uk/web/javascript/guide/iterators_and_generators/index.html new file mode 100644 index 0000000000..144a8c9ee0 --- /dev/null +++ b/files/uk/web/javascript/guide/iterators_and_generators/index.html @@ -0,0 +1,214 @@ +--- +title: Ітератори та генератори +slug: Web/JavaScript/Guide/Iterators_and_Generators +tags: + - JavaScript + - Посібник +translation_of: Web/JavaScript/Guide/Iterators_and_Generators +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Using_promises", "Web/JavaScript/Guide/Meta_programming")}}
+ +

Обробка кожного елемента колекції є дуже розповсюдженою операцією. JavaScript надає численні способи перебору колекції, від простих циклів {{jsxref("Statements/for","for")}} до {{jsxref("Global_Objects/Array/map","map()")}} та {{jsxref("Global_Objects/Array/filter","filter()")}}. Ітератори та генератори додають концепцію перебору безпосередньо у базову мову та надають механізм налаштування поведінки циклів {{jsxref("Statements/for...of","for...of")}}.

+ +

Більш детально дивіться у статтях:

+ + + +

Ітератори

+ +

У JavaScript ітератор - це об'єкт, який визначає послідовність та, за бажанням, значення, що повертається по її завершенні. Якщо конкретніше, то ітератор - це будь-який об'єкт, що реалізує протокол ітератора, маючи метод next(), який повертає об'єкт з двома властивостями: value, наступне значення послідовності; та done, що дорівнює true, якщо останнє значення послідовності вже було отримане. Якщо поруч з done присутнє значення value, воно є поверненим значенням ітератора.

+ +

Як тільки ітератор був створений, його можна явно обходити, викликаючи метод next(). Перебір ітератора називають споживанням ітератора, бо, загалом, це можна зробити лише один раз. Після того, як завершувальне значення було видане, додаткові виклики next() мають просто вертати {done: true}.

+ +

Найтиповішим ітератором у Javascript є ітератор масиву, який просто повертає по черзі кожне значення відповідного масиву. Хоча легко уявити, що усі ітератори можна виразити у вигляді масивів, це не так. Масиви мають бути розташовані у пам'яті цілком, але ітератори споживаються лише за необхідності і, таким чином, можуть виражати послідовності необмеженого розміру, такі як діапазон цілих чисел між 0 та Infinity (нескінченністю).

+ +

Ось приклад, який може робити саме це. Він дозволяє створювати ітератор простого діапазону, який визначає послідовність цілих чисел від start (включно) до end (не включно) з проміжком step. Його кінцеве повернене значення є розміром створеної послідовності, що відслідковується змінною iterationCount.

+ +
function makeRangeIterator(start = 0, end = Infinity, step = 1) {
+    let nextIndex = start;
+    let iterationCount = 0;
+
+    const rangeIterator = {
+       next: function() {
+           let result;
+           if (nextIndex < end) {
+               result = { value: nextIndex, done: false }
+               nextIndex += step;
+               iterationCount++;
+               return result;
+           }
+           return { value: iterationCount, done: true }
+       }
+    };
+    return rangeIterator;
+}
+ +

Далі використання ітератора виглядає наступним чином:

+ +
let it = makeRangeIterator(1, 10, 2);
+
+let result = it.next();
+while (!result.done) {
+ console.log(result.value); // 1 3 5 7 9
+ result = it.next();
+}
+
+console.log("Перебрано послідовність розміром: ", result.value); // [повертає 5 чисел з інтервалу від 0 до 10]
+
+
+ +
+

Неможливо знати, чи певний об'єкт є ітератором. Якщо вам необхідно це зробити, використовуйте ітерабельні об'єкти.

+
+ +

Функції-генератори

+ +

Хоча користувацькі ітератори є потужним інструментом, їхнє створення вимагає обережного програмування через необхідність явно підтримувати їхній внутрішній стан. Функції-генератори надають потужну альтернативу: вони дозволяють визначати алгоритм перебору написанням єдиної функції, виконання якої не є безперервним. Функції-генератори пишуться за допомогою синтаксису {{jsxref("Statements/function*","function*")}}. При першому виклику функції-генератори не виконують свій код, замість цього вони повертають ітератор під назвою Generator. Коли значення споживається викликом методу об'єкта Generator next, функція-генератор виконується до тих пір, поки не зустріне ключове слово yield.

+ +

Функція може викликатись будь-яку бажану кількість раз та кожен раз вертатиме новий об'єкт Generator, однак, кожний об'єкт Generator може перебиратись лише один раз.
+
+ Тепер ми можемо адаптувати наведений вище приклад. Поведінка коду ідентична, але ця реалізація набагато простіша у написанні та читанні.

+ +
function* makeRangeIterator(start = 0, end = 100, step = 1) {
+    let iterationCount = 0;
+    for (let i = start; i < end; i += step) {
+        iterationCount++;
+        yield i;
+    }
+    return iterationCount;
+}
+ +

Ітерабельні об'єкти

+ +

Об'єкт є ітерабельним, якщо він визначає свою ітераційну поведінку, наприклад, через які значення проходитиме цикл {{jsxref("Statements/for...of", "for...of")}}. Деякі вбудовані типи, такі як {{jsxref("Array")}} або {{jsxref("Map")}}, мають визначену за замовчуванням ітераційну поведінку, в той час, як інші типи (такі як {{jsxref("Object")}}) її не мають.

+ +

Для того, щоб бути ітерабельним, об'єкт повинен реалізувати метод @@iterator, тобто, цей об'єкт (або один з об'єктів у його ланцюжку прототипів) повинен мати властивість з ключем {{jsxref("Symbol.iterator")}}.
+
+ Може бути можливо перебрати ітерабельний об'єкт більше одного разу, або лише один раз. Який варіант обирати, вирішує програміст. Ітерабельні об'єкти, які можна перебрати лише один раз (наприклад, об'єкти Generator) традиційно повертають this зі свого методу @@iterator, тоді як ті, які можна перебирати багаторазово, повинні повертати новий ітератор на кожний виклик @@iterator.

+ +
function* makeIterator() {
+    yield 1;
+    yield 2;
+}
+
+const it = makeIterator();
+
+for(const itItem of it) {
+    console.log(itItem);
+}
+
+console.log(it[Symbol.iterator]() === it) // true;
+
+// Це приклад показує, що генератор(ітератор) є ітерабельним об'єктом, метод якого @@iterator повертає сам об'єкт (it),
+// і з цієї причини цей об'єкт (it) можна перебирати лише один раз
+
+
+// Якщо ми змінимо метод @@iterator об'єкта "it" на функцію/генератор, що вертає новий ітератор/генератор, цей об'єкт (it)
+// можна буде перебирати багато разів
+
+it[Symbol.iterator] = function* () {
+  yield 2;
+  yield 1;
+};
+
+ +

Створені користувачем ітерабельні об'єкти

+ +

Ми можемо створювати власні ітерабельні об'єкти наступним чином:

+ +
var myIterable = {
+    *[Symbol.iterator]() {
+        yield 1;
+        yield 2;
+        yield 3;
+    }
+}
+
+for (let value of myIterable) {
+    console.log(value);
+}
+// 1
+// 2
+// 3
+
+або
+
+[...myIterable]; // [1, 2, 3]
+
+ +

Вбудовані ітерабельні об'єкти

+ +

{{jsxref("String")}}, {{jsxref("Array")}}, {{jsxref("TypedArray")}}, {{jsxref("Map")}} та {{jsxref("Set")}} усі є вбудованими ітерабельними об'єктами, тому що всі їхні прототипи мають метод {{jsxref("Symbol.iterator")}}.

+ +

Синтаксис, що очікує на ітерабельний об'єкт

+ +

Деякі оператори та вирази очікують на ітерабельні об'єкти, наприклад, цикли {{jsxref("Statements/for...of","for-of")}}, {{jsxref("Operators/yield*","yield*")}}.

+ +
for (let value of ['а', 'б', 'в']) {
+    console.log(value);
+}
+// "а"
+// "б"
+// "в"
+
+[...'абв']; // ["а", "б", "в"]
+
+function* gen() {
+  yield* ['а', 'б', 'в'];
+}
+
+gen().next(); // { value: "а", done: false }
+
+[a, b, c] = new Set(['а', 'б', 'в']);
+a; // "а"
+
+
+ +

Просунуті генератори

+ +

Генератори обчислюють значення, які видають, на вимогу, це дозволяє їм ефективно відображати послідовності, затратні для обчислення, чи навіть нескінченні послідовності, як було продемонстровано вище.

+ +

Метод {{jsxref("Global_Objects/Generator/next","next()")}} також приймає значення, які можуть використовуватись для модифікації внутрішнього стану генератора. Значення, передане у метод next() буде отримане оператором yield. Зауважте, що значення, передане у перший метод next(), завжди ігнорується.

+ +

Ось генератор Фібоначчі, який використовує next(x), щоб перезапустити послідовність:

+ +
function* fibonacci() {
+  var fn1 = 0;
+  var fn2 = 1;
+  while (true) {
+    var current = fn1;
+    fn1 = fn2;
+    fn2 = current + fn1;
+    var reset = yield current;
+    if (reset) {
+        fn1 = 0;
+        fn2 = 1;
+    }
+  }
+}
+
+var sequence = fibonacci();
+console.log(sequence.next().value);     // 0
+console.log(sequence.next().value);     // 1
+console.log(sequence.next().value);     // 1
+console.log(sequence.next().value);     // 2
+console.log(sequence.next().value);     // 3
+console.log(sequence.next().value);     // 5
+console.log(sequence.next().value);     // 8
+console.log(sequence.next(true).value); // 0
+console.log(sequence.next().value);     // 1
+console.log(sequence.next().value);     // 1
+console.log(sequence.next().value);     // 2
+ +

Ви можете змусити генератор викинути виняток, викликавши його метод {{jsxref("Global_Objects/Generator/throw","throw()")}} та передавши значення винятку, яке він має викинути. Цей виняток буде викинутий з поточного призупиненого контексту генератора, так, якби поточний оператор зупинки yield був оператором throw значення.

+ +

Якщо виняток не перехоплений всередині генератора, він поширюватиметься до виклику throw(), і наступні виклики методу next() отримають властивість done, що дорівнює true.

+ +

Генератори мають метод {{jsxref("Global_Objects/Generator/return","return(value)")}}, який повертає надане значення та завершує сам генератор.

+ +

{{PreviousNext("Web/JavaScript/Guide/Using_promises", "Web/JavaScript/Guide/Meta_programming")}}

diff --git a/files/uk/web/javascript/guide/loops_and_iteration/index.html b/files/uk/web/javascript/guide/loops_and_iteration/index.html new file mode 100644 index 0000000000..1b76102c0d --- /dev/null +++ b/files/uk/web/javascript/guide/loops_and_iteration/index.html @@ -0,0 +1,355 @@ +--- +title: Цикли та ітерації +slug: Web/JavaScript/Guide/Loops_and_iteration +tags: + - JavaScript + - Інструкція + - Синтаксис + - Цикл +translation_of: Web/JavaScript/Guide/Loops_and_iteration +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}
+ +

Цикли пропонують швидкий та легкий спосіб робити щось неодноразово. Ця глава посібника JavaScript  представляє різні ітераційні оператори, доступні в JavaScript.

+ +

Ви можете уявити цикли комп'ютерною версією гри, де ви кажете комусь зробити X кроків в одному напрямку, а потім Y кроків в іншому; наприклад, ідею піти 5 кроків на схід можна задати циклом:

+ +
var step;
+for (step = 0; step < 5; step++) {
+  // Іти 5 разів від значення 0 до 4.
+  console.log('Іти на схід 1 крок');
+}
+
+ +

Є багато різних видів циклів, але вони всі роблять істотно одне і те ж саме: вони повторюють дію певну кількість разів (можливо, 0 разів!) . Механізми різних циклів пропонують різні способи задати початкову і кінцеву точку циклу. Є різні ситуації, які легко вирішуються тим чи іншим циклом.

+ +

Оператори циклів у JavaScript:

+ + + +

Оператор for

+ +

Цикл {{jsxref("statements/for","for")}} повторюється, доки певний вираз не стане false. Цикл for у JavaScript подібний до циклу  for у мовах Java і C. Має такий вигляд:

+ +
for ([початковийВираз(initialExpression)]; [умова(condition)]; [приріст(incrementExpression)])
+  інструкція(statement)
+
+ +

Коли цикл for виконується, відбувається наступне:

+ +
    +
  1. Виконується вираз initialExpression, якщо він заданий. Цей вираз зазвичай ініціалізує один або кілька лічильників, але синтаксис допускає вирази будь-якого рівня складності. Цей вираз також дозволяє оголошувати змінні.
  2. +
  3. Оцінюється вираз condition. Якщо вираз приймає значення  true,  ітерація циклу виконується, якщо false - цикл завершується.
  4. +
  5. Виконується statement. Щоб виконати кілька інструкцій, використовуйте ({ ... }), щоб згрупувати їх.
  6. +
  7. Потім виконується  вираз incrementExpression.
  8. +
  9. Далі все повертається до кроку 2.
  10. +
+ +

Приклад

+ +

Наступна функція містить вираз for, що рахує цифри вибраних варіантів в прокручуваному списку (елемента  {{HTMLElement("select")}} , що дозволяє мультивибір). Вираз for  оголошує змінну i і задає їй значення 0. Перевіряється чи i менша чим кількість виборів в елементі <select> , виконує наступний вираз ifта збільшує i на одиницю після кожного кроку цикла.

+ +
<form name="selectForm">
+  <p>
+    <label for="musicTypes">Виберіть деякі музичні жанри, а потім натисніть на кнопку нижче:</label>
+    <select id="musicTypes" name="musicTypes" multiple="multiple">
+      <option selected="selected">R&B</option>
+      <option>Jazz</option>
+      <option>Blues</option>
+      <option>New Age</option>
+      <option>Classical</option>
+      <option>Opera</option>
+    </select>
+  </p>
+  <p><input id="btn" type="button" value="Скільки ви вибрали?" /></p>
+</form>
+
+<script>
+function howMany(selectObject) {
+  var numberSelected = 0;
+  for (var i = 0; i < selectObject.options.length; i++) {
+    if (selectObject.options[i].selected) {
+      numberSelected++;
+    }
+  }
+  return numberSelected;
+}
+
+var btn = document.getElementById('btn');
+btn.addEventListener('click', function() {
+  alert('Кількість вибраних варіагьів: ' + howMany(document.selectForm.musicTypes));
+});
+</script>
+
+
+ +

Оператор do...while

+ +

Оператор {{jsxref("statements/do...while", "do...while")}} повторює дії поки певна умова не прийме значення false. Оператор do...while виглядатиме наступним чином:

+ +
do
+  statement
+while (condition);
+
+ +

statement завжди виконується принаймні один раз перед тим як умова буде перевірена (і потім знову поки умова не прийме false). Щоб виконати кілька виразів необхідно використати ({ ... })  щоб згрупувати ці вирази.  Якщо condition приймає значення true, тіло цикла виконується повторно. В кінці всіх виконань вираз перевіряється. Коли вираз приймає false, ітерації цикла do...while зупиняються.

+ +

Приклади

+ +

В наступному прикладі цикл do ітерується принаймні один раз і повторюється доки i менша чим 5.

+ +
var i = 0;
+do {
+  i += 1;
+  console.log(i);
+} while (i < 5);
+ +

Оператор while

+ +

Вираз {{jsxref("statements/while","while")}} виконується доти доки спеціальна умова приймає значення true. Вираз while виглядає наступним чином:

+ +
while (condition)
+  statement
+
+ +

Якщо умова стає false, statement перестає виконуватись і відбувається вихід із цикла.

+ +

Вираз перевіряється перед тим як виконається тіло цикла. Якщо вираз повертає true, statement виконується і умова тестується заново. Якщо вираз повертає false, виконання зупиняється і відбувається вихід з циклу while.

+ +

Щоб виконати кілька виразів в циклі використовуйте ({ ... }), щоб згрупувати їх.

+ +

Приклад 1

+ +

Наступний цикл while виконує цикл доти доки n менше трьох:

+ +
var n = 0;
+var x = 0;
+while (n < 3) {
+  n++;
+  x += n;
+}
+
+ +

З кожною ітерацією, цикл збільшує n, та додає це до значення x. Тому, x і n приймають наступні значення:

+ + + +

Після третьої ітерації умова n < 3 більше не true, тому цикл припиняється.

+ +

Приклад 2

+ +

Уникайте безкінечних циклів. Переконайтесь, що вираз в циклі прийме значення false; інакше вихід з цикла ніколи не відбудеться. Вираз в наступному циклі while виконуватиметься постійно тому, що умова ніколи не стане false:

+ +
while (true) {
+  console.log('Hello, world!');
+}
+ +

Оператор labeled

+ +

 {{jsxref("statements/label","label")}} забезпечує вираз з ідентифікатором, що дозволяє вам зсилатися до цього місця з будь-якого місця вашої програми. Наприклад, ви можете використати label, щоб позначити цикл, а потім скористатися операторами break або continue, щоб вказати, чи повинна програма переривати цей цикл або продовжувати його виконання.

+ +

Синтаксис оператора виглядає наступним чином:

+ +
label :
+   statement
+
+ +

Значення label може бути будь-яким ідентифікатором JavaScript, що не є зарезервованим словом. statement, який ви ідентифікуєте може бути будь-яким виразом.

+ +

Приклад

+ +

В цьому прикладі позначка markLoop ідентифікує цикл while.

+ +
markLoop:
+while (theMark == true) {
+   doSomething();
+}
+ +

Оператор break

+ +

Використовуйте оператор {{jsxref("statements/break","break")}} для виходу з циклу, switch, чи в поєднанні з оператором label.

+ + + +

Синтаксис оператора break виглядає наступним чином:

+ +
break [label];
+
+ +

Перша форма синтаксису завершує перший батьківський цикл, або оператор switch; Друга форма завершує певний оператор позначений за допомогоюю label.

+ +

Приклад 1

+ +

Наступний приклад проходиться по елементам масива доки не знайде індекс елемента значення якого співпадає із значенням theValue:

+ +
for (var i = 0; i < a.length; i++) {
+  if (a[i] == theValue) {
+    break;
+  }
+}
+ +

Приклад 2: Переривання позначки

+ +
var x = 0;
+var z = 0;
+labelCancelLoops: while (true) {
+  console.log('Зовнішні цикли: ' + x);
+  x += 1;
+  z = 1;
+  while (true) {
+    console.log('Внутрішні цикли: ' + z);
+    z += 1;
+    if (z === 10 && x === 10) {
+      break labelCancelLoops;
+    } else if (z === 10) {
+      break;
+    }
+  }
+}
+
+ +

Оператор continue

+ +

Оператор {{jsxref("statements/continue","continue")}} може використовуватись для перезапуску while, do-while, for, чи виразу label.

+ + + +

Синтаксис оператора continue виглядає наступним чином:

+ +
continue [label];
+
+ +

Приклад 1

+ +

Наступний приклад показує цикл while з оператором continue, що виконується коли значення i дорівнює трьом. Тоді як, n приймає значення 1, 3, 7, 12.

+ +
var i = 0;
+var n = 0;
+while (i < 5) {
+  i++;
+  if (i == 3) {
+    continue;
+  }
+  n += i;
+  console.log(n);
+}
+//1,3,7,12
+
+
+var i = 0;
+var n = 0;
+while (i < 5) {
+  i++;
+  if (i == 3) {
+     // continue;
+  }
+  n += i;
+  console.log(n);
+}
+// 1,3,6,10,15
+
+ +

Приклад 2

+ +

Вираз позначений checkiandj містить вираз позначений checkj. Якщо continue зустрічається програма зупинить ітерацію checkj і почнеться з наступної ітерації. Кожен раз як continue зустрічається, checkj переітеровується поки вираз не поверне false. Коли false повертається, решта виразу checkiandj виконується іcheckiandj переітеровується доки умова не поверне false. Колиfalse повертається програма продовжує  вираз слідуючогоcheckiandj.

+ +

Якщо continue має label checkiandj, програма буде продовжуватись зверху виразаcheckiandj.

+ +
var i = 0;
+var j = 10;
+checkiandj:
+  while (i < 4) {
+    console.log(i);
+    i += 1;
+    checkj:
+      while (j > 4) {
+        console.log(j);
+        j -= 1;
+        if ((j % 2) == 0) {
+          continue checkj;
+        }
+        console.log(j + ' is odd.');
+      }
+      console.log('i = ' + i);
+      console.log('j = ' + j);
+  }
+ +

Оператор for...in

+ +

Оператор {{jsxref("statements/for...in","for...in")}} ітерує певну змінну по усіх перечислювальних властивостях об'єкта. Для кожної окремої властивості JavaScript виконує певний вираз. Операторfor...in виглядає наступним чином:

+ +
for (variable in object) {
+  statements
+}
+
+ +

Приклад

+ +

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

+ +
function dump_props(obj, obj_name) {
+  var result = '';
+  for (var i in obj) {
+    result += obj_name + '.' + i + ' = ' + obj[i] + '<br>';
+  }
+  result += '<hr>';
+  return result;
+}
+
+ +

Для об'єкту car з властивостями make і model, result результат буде:

+ +
car.make = Ford
+car.model = Mustang
+
+ +

Масиви

+ +

Також це може підходити для ітерування елементів {{jsxref("Array")}}, Оператор for...in буде повертати ім'я визначених користувачем властивостей і додаткових номерних індексів. Таким чином, краще використовувати традиційний цикл {{jsxref("statements/for","for")}} з номерними індексами коли ітеруєте масив, так як for...in ітерує властивості окрім елементів масиву, якщо ви змінюєте об'єкт масиву, наприклад, додаючи нові властивості чи методи.

+ +

Оператор for...of

+ +

Оператор {{jsxref("statements/for...of","for...of")}} створює цикл, що проходиться по ітерованому об'єкту (включно з {{jsxref("Array")}}, {{jsxref("Map")}}, {{jsxref("Set")}}, об'єкт {{jsxref("functions/arguments","arguments")}} і т.д), викликаючи в кожній ітерації функцію з виразами для значення кожної окремої властивості.

+ +
for (variable of object) {
+  statement
+}
+ +

Наступний приклад показує різницю між циклами for...of і {{jsxref("statements/for...in","for...in")}}. У той час як for...in проходиться по іменах властивостей, цикл for...of проходиться по значеннях цих властивостей:

+ +
var arr = [3, 5, 7];
+arr.foo = 'hello';
+
+for (var i in arr) {
+   console.log(i); // logs "0", "1", "2", "foo"
+}
+
+for (var i of arr) {
+   console.log(i); // logs 3, 5, 7
+}
+
+ +

{{PreviousNext("Web/JavaScript/Guide/Control_flow_and_error_handling", "Web/JavaScript/Guide/Functions")}}

+ +
+
+
diff --git a/files/uk/web/javascript/guide/numbers_and_dates/index.html b/files/uk/web/javascript/guide/numbers_and_dates/index.html new file mode 100644 index 0000000000..71b7acd1bc --- /dev/null +++ b/files/uk/web/javascript/guide/numbers_and_dates/index.html @@ -0,0 +1,383 @@ +--- +title: Числа та дати +slug: Web/JavaScript/Guide/Numbers_and_dates +tags: + - Date + - JavaScript + - Math + - Number + - Дати + - Обчислення + - Посібник + - Числа +translation_of: Web/JavaScript/Guide/Numbers_and_dates +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Вирази_та_оператори", "Web/JavaScript/Guide/Text_formatting")}}
+ +

У даному розділі представлені концепції, об'єкти та функції, які використовуються, щоб працювати та виконувати розрахунки з числами та датами у JavaScript. Це враховує використання чисел, записаних у різних системах числення, в тому числі десятковій, двійковій та шістнадцятковій, а також використання глобального об'єкта {{jsxref("Math")}} для виконання найрізноманітніших математичних операцій над числами.

+ +

Числа

+ +

У JavaScript, числа реалізовані у 64-бітному бінарному форматі IEEE 754 з подвійною точністю (тобто, число між ±2−1022 та ±2+1023, або приблизно від ±10−308 до ±10+308, з числовою точністю у 53 біти). Цілі значення до ±253 − 1 можуть бути відображені точно.

+ +

Додатково числовий тип має три символьні значення: +{{jsxref("Infinity")}}, -{{jsxref("Infinity")}} та {{jsxref("NaN")}} (not-a-number - не число).

+ +

Нещодавнім доповненням JavaScript є тип {{jsxref("BigInt")}}, який дає можливість оперувати з дуже великими цілими числами. Хоча існують застереження у використанні BigInt; наприклад, ви не можете змішувати та співставляти значення BigInt та {{jsxref("Number")}} в рамках однієї операції, і ви не можете використовувати об'єкт {{jsxref("Math")}} зі значеннями BigInt.

+ +

У статті Типи та структури даних в JavaScript числовий тип даних описаний в контексті інших примітивних типів JavaScript.

+ +

Ви можете використовувати чотири типа числових літералів: десяткові, двійкові, вісімкові та шістнадцятковий.

+ +

Десяткові числа

+ +
1234567890
+42
+
+// Будьте уважні при використанні нулів на початку числа
+
+0888 // 888 розбирається як десяткове число
+0777 // розбирається як вісімкове число у нестрогому режимі (десяткове число 511)
+ +

Зверніть увагу, що десятковий літерал може починатися з нуля (0) за яким розташована інша десяткова цифра, але, якщо кожна цифра після 0 менша за 8, то число розбирається як вісімкове.

+ +

Двійкові числа

+ +

Синтаксис двійковичх чисел використовує нуль попереду, за яким розташована латинська буква "B" (0b або 0B). Якщо цифри після 0b не є 0 або 1, викидається наступний виняток SyntaxError: "Missing binary digits after 0b".

+ +
var FLT_SIGNBIT  = 0b10000000000000000000000000000000; // 2147483648
+var FLT_EXPONENT = 0b01111111100000000000000000000000; // 2139095040
+var FLT_MANTISSA = 0B00000000011111111111111111111111; // 8388607
+ +

Вісімкові числа

+ +

Синтаксис вісімкових чисел теж використовує нуль попереду. Якщо числа після 0 не входять у діапазон від 0 до 7, то число буде інтерпретоване як десяткове.

+ +
var n = 0755; // 493
+var m = 0644; // 420
+ +

Строгий режим у ECMAScript 5 забороняє вісімковий синтаксис. Вісімковий синтаксис не є частиною ECMAScript 5, але він підтримується всіма переглядачами додаванням нуля попереду вісімкового числа: 0644 === 420, а "\045" === "%". У ECMAScript 2015 вісімкові значення підтримуються, якщо вони мають префікс 0o, наприклад: 

+ +
var a = 0o10; // ES2015: 8
+ +

Шістнадцяткові числа

+ +

Синтаксис шістнадцяткових чисел використовує нуль попереду, за яким розташована латинська літера "X" (0x або 0X). Якщо числа після 0x не входять у діапазон (0123456789ABCDEF), то буде викинутий наступний виняток SyntaxError: "Identifier starts immediately after numeric literal".

+ +
0xFFFFFFFFFFFFFFFFF // 295147905179352830000
+0x123456789ABCDEF   // 81985529216486900
+0XA                 // 10
+ +

Експоненціальний запис

+ +
1E3   // 1000
+2e6   // 2000000
+0.1e2 // 10
+ +

Об'єкт Number

+ +

Вбудований об'єкт {{jsxref("Число", "Number")}} має властивості для числових констант, такі як масимальне числове значення, не-число (not-a-number) та нескінченність. Ви не можете змінювати значення цих властивостей і використовуєте їх наступним чином:

+ +
var biggestNum = Number.MAX_VALUE;
+var smallestNum = Number.MIN_VALUE;
+var infiniteNum = Number.POSITIVE_INFINITY;
+var negInfiniteNum = Number.NEGATIVE_INFINITY;
+var notANum = Number.NaN;
+ +

Ви завжди посилаєтесь на властивість попередньо визначенного об'єкта Number, як це показано вище, а не на властивість об'єкта Number, створеного вами.

+ +

Наступна таблиця підсумовує властивості об'єкта Number.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Властивості Number
ВластивістьОпис
{{jsxref("Число.MAX_VALUE", "Number.MAX_VALUE")}}Найбільше число, доступне для відображення (±1.7976931348623157e+308)
{{jsxref("Число.MIN_VALUE", "Number.MIN_VALUE")}} +

Найменше число, доступне для відображення (±5e-324)

+
{{jsxref("Число.NaN", "Number.NaN")}}Спеціальне значення "не-число" (not-a-number)
{{jsxref("Число.NEGATIVE_INFINITY", "Number.NEGATIVE_INFINITY")}}Спеціальне значення від'ємна нескінченність; повертається при переповненні
{{jsxref("Число.POSITIVE_INFINITY", "Number.POSITIVE_INFINITY")}}Спеціальне значення додатна нескінченність; повертається при переповненні
{{jsxref("Число.EPSILON", "Number.EPSILON")}}Різниця між 1 та найменшим числом, більшим за 1, що може бути представлене об'єктом {{jsxref("Число", "Number")}} (2.220446049250313e-16)
{{jsxref("Число.MIN_SAFE_INTEGER", "Number.MIN_SAFE_INTEGER")}}Мінімальне ціле безпечне число у JavaScript (−253 + 1 або −9007199254740991)
{{jsxref("Число.MAX_SAFE_INTEGER", "Number.MAX_SAFE_INTEGER")}}Максимальне ціле безпечне число у JavaScript (+253 − 1 або +9007199254740991)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Методи Number
МетодОпис
{{jsxref("Число.parseFloat()", "Number.parseFloat()")}}Розбирає рядковий аргумент та повертає число з плаваючою крапкою, яке вдалося розпізнати.
+ Аналог глобальної функції {{jsxref("parseFloat", "parseFloat()")}}.
{{jsxref("Число.parseInt()", "Number.parseInt()")}}Розбирає рядковий аргумент та поверає ціле число в заданій системі числення.
+ Аналог глобальної функції {{jsxref("parseInt", "parseInt()")}}.
{{jsxref("Число.isFinite()", "Number.isFinite()")}}Визначає, чи є передане значення скінченним числом.
{{jsxref("Число.isInteger()", "Number.isInteger()")}}Визначає, чи є передане значення цілим числом.
{{jsxref("Число.isNaN()", "Number.isNaN()")}}Визначає, чи є передане значення {{jsxref("Global_Objects/NaN", "NaN")}}. Більш надійніша версія оригінальної глобальної функції  {{jsxref("Global_Objects/isNaN", "isNaN()")}}.
{{jsxref("Число.isSafeInteger()", "Number.isSafeInteger()")}}Визначає, чи є передане значення безпечним цілим числом.
+ +

Прототип Number надає методи для отримання інформації з об'єктів Number різноманітних форматів. Наступна таблиця наводить методи Number.prototype.

+ + + + + + + + + + + + + + + + + + + + + + + +
Методи Number.prototype
МетодиОпис
{{jsxref("Число.toExponential", "toExponential()")}}Повертає рядок, що експоненціальний запис числа.
{{jsxref("Число.toFixed", "toFixed()")}}Повертає рядок, що містить запис числа у форматі з нерухомою крапкою.
{{jsxref("Число.toPrecision", "toPrecision()")}}Повертає рядок, що містить запис числа із зазначеною точністю у форматі з нерухомою крапкою.
+ +

Об'єкт Math

+ +

Вбудований об'єкт {{jsxref("Math")}} має властивості та методи для математичних констант та функцій. Наприклад, властивість PI об'єкту Math має значення пі (3.141...), яке використовується у застосунку так:

+ +
Math.PI
+ +

Аналогічно, стандартні математичні функції є методами об'єкта Math. Сюди входять тригонометричні, логарифмічні, експоненціальні та інші функції. Наприклад, якби вам знадобилась тригонометрична функція сінус, ви б написали

+ +
Math.sin(1.56)
+ +

Зверніть увагу, що всі тригонометричні методи об'єкта Math в якості аргументів приймають величини в радіанах.

+ +

В даній таблиці наведені методи об'єкта Math.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Методи Math
МетодиОпис
{{jsxref("Math.abs", "abs()")}}Абсолютне значення
{{jsxref("Math.sin", "sin()")}}, {{jsxref("Math.cos", "cos()")}}, {{jsxref("Math.tan", "tan()")}}Стандартні тригонометричні функції; з аргументом в радіанах
{{jsxref("Math.asin", "asin()")}}, {{jsxref("Math.acos", "acos()")}}, {{jsxref("Math.atan", "atan()")}}, {{jsxref("Math.atan2", "atan2()")}}Обернені тригонометричні функції; повертають значення в радіанах.
{{jsxref("Math.sinh", "sinh()")}}, {{jsxref("Math.cosh", "cosh()")}}, {{jsxref("Math.tanh", "tanh()")}}Гіперболічні функції; аргумент - гіперболічний кут.
{{jsxref("Math.asinh", "asinh()")}}, {{jsxref("Math.acosh", "acosh()")}}, {{jsxref("Math.atanh", "atanh()")}}Зворотні, гіперболічні функцій; повертають гіперболічний кут.
+

{{jsxref("Math.pow", "pow()")}}, {{jsxref("Math.exp", "exp()")}}, {{jsxref("Math.expm1", "expm1()")}}, {{jsxref("Math.log10", "log10()")}}, {{jsxref("Math.log1p", "log1p()")}}, {{jsxref("Math.log2", "log2()")}}

+
Експоненційні та логарифмічні фукнції.
{{jsxref("Math.floor", "floor()")}}, {{jsxref("Math.ceil", "ceil()")}}Повертає найбільне/найменше ціле, яке менше/більше або дорівнює аргументу.
{{jsxref("Math.min", "min()")}}, {{jsxref("Math.max", "max()")}}Повертає мінімальне або максимальне (відповідно) значення зі списку розділених комою чисел, переданих як аргумент.
{{jsxref("Math.random", "random()")}}Повертає випадкове число в інтервалі між 0 та 1.
{{jsxref("Math.round", "round()")}}, {{jsxref("Math.fround", "fround()")}}, {{jsxref("Math.trunc", "trunc()")}},Фукнції округлення та обрізання.
{{jsxref("Math.sqrt", "sqrt()")}}, {{jsxref("Math.cbrt", "cbrt()")}}, {{jsxref("Math.hypot", "hypot()")}} +

Квадратний корінь, кубічний корінь, корінь квадратний з суми квадратів аргументів.

+
{{jsxref("Math.sign", "sign()")}}Знак числа, що вказує, чи є число додатним, від'ємним, чи нулем.
{{jsxref("Math.clz32", "clz32()")}},
+ {{jsxref("Math.imul", "imul()")}}
Кількість перших нульових бітів у 32-бітному двійковому представлені.
+ Результат C-подібного 32-бітного множення двох аргументів.
+ +

На відміну від багатьох інших об'єктів, вам не потрібно створювати екземпляри об'єкта Math. Завжди слід використоввати вбудований глобальний об'єкт Math безпосередньо.

+ +

Об'єкт Date

+ +

JavaScript не має окремого типу даних для дат. Однак, ви можете скористатись об'єктом {{jsxref("Date")}} та його методами для роботи з датою та часом у вашому проекті. Об'єкт Date має величезну кількість методів для встановлення, отримання та маніпулювання датами, але не має жодних властивостей.

+ +

JavaScript оперує датами подібно до Java. Ці дві мови програмування мають багато подібних методів та зберігають дату як кількість мілісекунд, що минули з 00:00:00 1 січня 1970 року, в той час, як часова мітка Unix позначає кількість секунд, що минули з 00:00:00 1 січня 1970 року.

+ +

Інтервал значень, які може приймати об'єкт Date, знаходиться від -100,000,000 до 100,000,000 днів відносно 1 січня 1970 року за UTC.

+ +

Щоб створити об'єкт Date:

+ +
var dateObjectName = new Date([parameters]);
+ +

де dateObjectName - це ім'я створеного об'єкта Date; це може бути як новий об'єкт, так і властивість вже існуючого об'єкта.

+ +

Виклик Date без оператора new повертає теперішню дату та час у вигляді рядка.

+ +

Параметри (parameters) у наведеному записі можуть бути одним з наступних значень:

+ + + +

Методи об'єкта Date

+ +

Методи об'єкта Date для роботи з датами та часом підпадають під такі категорії:

+ + + +

За допомогою методів "get" та "set" можна встановлювати та отримувати значення секунд, хвилин, годин, днів місяця, днів тижня, місяць та рік окремо. Зверніть увагу на метод getDay, який повертає день тижня, але не існує відповідного методу setDay, оскільки день тижня визначається автоматично. Всі ці методи використовують цілі числа для представлення відповідних даних наступним чином:

+ + + +

Припустимо, ви визначаєте наступну дату:

+ +
var Xmas95 = new Date('December 25, 1995');
+ +

Тоді Xmas95.getMonth() повертає 11, а Xmas95.getFullYear() повертає 1995.

+ +

Методи getTime та setTime зручні для порівняння дат. Метод getTime повертає кількість мілесекунд від 00:00:00, 1 січня 1970 року.

+ +

Наприклад, наступний код показує, скільки днів залишилось у цьому році:

+ +
var today = new Date();
+var endYear = new Date(1995, 11, 31, 23, 59, 59, 999); // Встановлюємо день та місяць
+endYear.setFullYear(today.getFullYear()); // Встановлюємо цей рік
+var msPerDay = 24 * 60 * 60 * 1000; // Кількість мілісекунд в одному дні
+var daysLeft = (endYear.getTime() - today.getTime()) / msPerDay;
+var daysLeft = Math.round(daysLeft); //Повертає кількість днів, які залишилися в цьому році
+ +

Цей приклад створює об'єкт Date на ім'я today, який містить в собі сьогоднішню дату. Далі він створює об'єкт Date на ім'я endYear, якому присвоюється поточний рік. Потім, використовуючи кількість мілісекунд в одному дні, вираховує кількість днів між today та endYear, використовуючи getTime та округливши результат до цілого значення кількості днів.

+ +

Метод parse корисний для присвоєння рядкових значень існуючим об'єктам Date. Наприклад, наступний код використовує parse та setTime для присвоєння дати об'єкту IPOdate:

+ +
var IPOdate = new Date();
+IPOdate.setTime(Date.parse('Aug 9, 1995'));
+ +

Приклад

+ +

У наступному прикладі, функція JSClock() повертає час у форматі цифрового годинника.

+ +
function JSClock() {
+  var time = new Date();
+  var hour = time.getHours();
+  var minute = time.getMinutes();
+  var second = time.getSeconds();
+  var temp = '' + ((hour > 12) ? hour - 12 : hour);
+  if (hour == 0)
+    temp = '12';
+  temp += ((minute < 10) ? ':0' : ':') + minute;
+  temp += ((second < 10) ? ':0' : ':') + second;
+  temp += (hour >= 12) ? ' P.M.' : ' A.M.';
+  return temp;
+}
+ +

Функція JSClock спочатку створює новий об'єкт Date, який називається time; оскільки жодних аргументів не надано, час створюється на основі поточної дати та часу. Далі викликами методів getHours, getMinutes та getSeconds присвоюються значення поточної години, хвилини та секунди змінним hour, minute та second.

+ +

Наступні чотири інструкції створюють рядкове значення на основі значення часу. Перша інструкція створює змінну temp, присвоюючи їй значення за допомогою умовного виразу: якщо hour більше за 12, то (hour - 12), інакше просто hour, у випадку ж коли hour дорівнює 0, він набуває значення 12.

+ +

Наступна інструкція додає значення minute до змінної temp. Якщо значення minute менше за 10, умовний вираз додає рядок з нулем попереду; інакше додається рядок з двокрапкою для розмежування. Далі аналогічним чином інструкція додає до temp секунди.

+ +

Зрештою, умовний вираз додає "P.M." до temp, якщо hour дорівнює або більший за 12; інакше, додається "A.M.".

+ +

{{PreviousNext("Web/JavaScript/Guide/Вирази_та_оператори", "Web/JavaScript/Guide/Text_formatting")}}

diff --git a/files/uk/web/javascript/guide/regular_expressions/index.html b/files/uk/web/javascript/guide/regular_expressions/index.html new file mode 100644 index 0000000000..e41b342ac7 --- /dev/null +++ b/files/uk/web/javascript/guide/regular_expressions/index.html @@ -0,0 +1,635 @@ +--- +title: Регулярні Вирази +slug: Web/JavaScript/Guide/Regular_Expressions +translation_of: Web/JavaScript/Guide/Regular_Expressions +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}
+ +

Регулярні вирази це шаблони, що використовуються для пошуку збігу,співпадіння в тексті чи строках. В JavaScript регулярні вирази також є обʼєктами. Ці шаблони використовуются для пошуку збігу у тексті. Пропоную розібратись з  регулярними виразами JavaScript детальніше.

+ +

Створення регулярних виразів

+ +

Ви можете створювати регулярні вирази двома способами:

+ +

Використовуючи літерал регулярного виразу, який складається з шаблону між символами "/" слеш:

+ +
var re = /ab+c/;
+
+ +

Цей спосіб підійде для статичних, простих виразів, використовуйте його для покращення продуктивності.

+ +

Або через створення обʼєкта {{jsxref("RegExp")}}:

+ +
var re = new RegExp("ab+c");
+
+ +

В такому випадку створюєтся об'єкт з методами {{jsxref("RegExp.exec", "exec")}} та {{jsxref("RegExp.test", "test")}} класу {{jsxref("RegExp")}}, та методами з {{jsxref("String")}} классу, а саме {{jsxref("String.match", "match")}}, {{jsxref("String.replace", "replace")}}, {{jsxref("String.search", "search")}}, та {{jsxref("String.split", "split")}}. 

+ +

Використовуйте цей спосіб у випадках, коли вам відомо, що шаблон регулярного виразу буде змінюватись. Наприклад для очікування дій користувача з подальшим виконанням якоїсь функції тощо, або для побудови URL маршутів.

+ +

Створення шаблону регулярного виразу

+ +

Шаблон регулярного виразу складається зі звичайних символів, наприклад /abc/, або комбінації звичайних та спеціальних символів – /ab*c/ або /Chapter (\d+)\.\d*/. Останій приклад містить дужки, які використовуються як запамʼятовуючий пристрiй. Збіг з цією частиною шаблону запамʼятовується для подальшого використання, більш докладно про це в розділі {{ web.link("#Using_parenthesized_substring_matches", "Використання збігів підрядків у дужках") }}.

+ +

Використання простих шаблонів

+ +

Прості шаблони складаються з символів, для яких потрібно знайти прямий збіг. Наприклад, шаблон /abc/ збігається з комбінацією символів в рядку тільки у випадку, коли символи 'abc' опиняються поруч саме в такому порядку. Збіг буде успішним у рядках типу "Hi, do you know your abc's?" та "The latest airplane designs evolved from slabcraft." В обох випадках шаблон збігається з підрядком 'abc'. В рядку 'Grab crab' збігу не буде, так як він містить підрядок 'abc', що не збігається точно з послідовністю 'abc'.

+ +

Використання спеціальних символів

+ +

Коли пошук збігу вимагає чогось більшого ніж прямий збіг, наприклад пошук одного чи більше символу 'b', або пошуку пробілів, шаблон включає спеціальні символи. Так, шаблон /ab*c/ збігається з будь-якою символьною комбінацією, де за символом 'a' може бути багато повторів символу 'b' (* значить 0 чи більше випадків) за яким відразу йде символ 'c'. В рядку "cbbabbbbcdebc," шаблон збігається з підрядком 'abbbbc'.

+ +

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

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Спеціальні символи, що використовуються в регулярних виразах.
СимволЗначення
\ +

Відповідає одному з наступних правил:
+
+ Зворотній слеш означає що наступний символ є спеціальним та не сприймається буквально. Наприклад, 'b' без передуючого '\' збігається з літерою 'b' у нижньому регістрі. Але вираз '\b' не відповідає жодному збігу; він утворює спеціальний символ, що збігається з межею слова.
+
+ Так, шаблон /a*/ покладається на спецсимвол '*', щоб знайти збіг з 0 чи більше символів 'a'. На відміну від цього, щаблон /a\*/ усуває сприйняття '*', як спецсимвол, та дозволяє отримати збіг 'a*'.
+
+ Не забувайте екранувати символ '\' подвійним ' '\\' використовуючи його в нотації RegExp("pattern"), так як '\' є екрануючим символом в рядках.

+
^Шукати збіг окрім перед символом переносу рядка чи кінця строки.
+
+ Наприклад, /^A/ не має збігу з "an A", але має збіг в рядку "An E".
+
+ Символ '^' має також і інші значення, коли він вказуєтся на початку шаблону регулярного виразу. Ознайомтесь з розділом доповнений набір символів для отримання деталей та прикладів.
$ +

Вказує що на забігу має завершитись строка. 

+ +

Наприклад, /t$/ не збігається з 't' в "eater", але має збіг в "eat".

+
* +

Збіг повторюється 0 чи більше разів. Еквівалент {0,}.

+ +

Наприклад, /bo*/ збігається з 'boooo' в "A ghost booooed" та з 'b' in "A bird warbled", але не має збігу в "A goat grunted".

+
+ +

Відповідає попередньому символу, що повторюється щонайменше 1 чи більше разів. Еквівалент {1,}.

+ +

Наприклад, /a+/ збігається з 'a' в "candy" та з усіма 'a' в "caaaaaaandy", але не має збігів у "cndy".

+
?Пошук збігу 0 чи 1 раз. Еквівалент {0,1}.
+
+ Наприклад, /e?le?/ відповідає 'el' в "angel" та 'le' в "angle", а також 'l' в "oslo".
+
+ Якщо вказуєтся одразу після специмволів *, +, ?, або {}, робить їх більш суворими (збіг з найменш можливою кількістю символів), на відміну від типових результатів, на відміну від несуворих пошуків (збіг з максимально можливою кількістю символів). Наприклад, застосування /\d+/ (пошук повторення десятичної цифри багато разів) до "123abc" знайде "123". Але застосування /\d+?/ зробить його суворим і результом збігу буде перша цифра "1".
+  
. +

(дрібна крапка) вказує пошук будь-якого одного символу, окрім початку строки.

+ +

Наприклад, /.n/ відповідає 'an' та 'on' в рядку "nay, an apple is on the tree", але не знайде збігів у  'nay'.

+
(x) +

Пошук 'x' і запам'ятати збіг. Ці дужки також називають захоплюючи дужки.
+
+ '(foo)' та '(bar)' в шаблоні /(foo) (bar) \1 \2/ збігаються з першими двома словами в рядку "foo bar foo bar" та запамʼятовують їх.  А \1 та \2 в шаблоні відповідають двом останім словам. Зауважте, що \1, \2, \n використовуються в порівняльній частині регулярного виразу. В зміній частині регулярного виразу потрібно використовувати синтакс $1, $2, $n: 'bar foo'.replace( /(...) (...)/, '$2 $1' ).

+
(?:x)Відповідає 'x', але не запамʼятовує збіг. Такий випадок називається незахоплючими дужками, і дозволяє вам визначати під-вирази для роботи з операторами ругулярних виразів. Розглянемо приклад /(?:foo){1,2}/. Якщо б шаблон був /foo{1,2}/, символи {1,2} застосовувались би тільки до останього символу 'o' в 'foo'. В незахоплюючих дужках {1,2} застосовується до всього слова 'foo'.
x(?=y) +

Відповідає 'x' тільки якщо за 'x' йде 'y'. Це називається випередження.

+ +

Наприклад, /Jack(?=Sprat)/ збігатиметься з 'Jack' тількя якщо за ним йде 'Sprat'. /Jack(?=Sprat|Frost)/ збігається з 'Jack' тільки якщо за ним йде 'Sprat' або 'Frost'. Проте, а ні 'Sprat', а ні 'Frost' не є частиною результату збігу.

+
x(?!y) +

Відповідає 'x' тільки якщо за 'x' не йде 'y'. Це називається відʼємним випередженням.

+ +

Наприклад, /\d+(?!\.)/ матиме збіг з числом тільки якщо за ним відсутня десяткова точка. Регулярний вираз /\d+(?!\.)/.exec("3.141") матиме збіг з '141', але не з '3.141'.

+
x|y +

Відповідає 'x' або 'y'.

+ +

Наприклад, /green|red/ збігається з 'green' в "green apple" та з 'red' в "red apple."

+
{n}Відповідає точній кількості n повторень попереднього виразу. N повино бути додатним цілим числом.
+
+ Наприклад, /a{2}/ не матиме збігів для 'a' в "candy," але збігатиметься з усіма a в "caandy," та двом першим a в "caaandy."
{n,m} +

Де n та m – додатні цілі числа та n <= m. Відповідає що найменше n та до m включно повторень передуючого виразу. Якщо m немає, вважається що m = ∞.

+ +

Наприклад, /a{1,3}/ не збігається з рядком "cndy", відповідає 'a' в "candy," та першим двом a в "caandy," а також першим трьом a в "caaaaaaandy". Зауважте що під час порівняння "caaaaaaandy", відповідає лише "aaa", навіть якщо оригінальний рядок містить довший рядок з a.

+
[xyz]Набір символів. Відповідає збігу з будь-яким із символів шаблону, включаючи керуючі послідовності. Спеціальні символи такі як точка (.) та зірочка (*) не є спецсимволами в середині набору символів та не потребують екранування. Ви можете задавати послідовності використовуючи дефіс, як в наступному прикладі.
+
+ Шаблон [a-d], що представляє теж саме що й [abcd], збігається з 'b' в "brisket" та з 'c' в "city". Шаблони /[a-z.]+/ та /[\w.]+/ збігаються зі всім рядком "test.i.ng".
[^xyz] +

Відʼємний або компліментарний набір змін. Цей вираз відповідає збігу з будь-чим що не міститься в квадратних дужках. Ви можете зазначити діапазон використовуючи дефіс. Все що працює зі звичайним набором символів спрацює і в цьому випадку.

+ +

Наприклад, [^abc] теж саме що й [^a-c]. Вони відповідають збігу 'r' в "brisket" та 'h' в "chop."

+
[\b]Відповідає символу backspace (U+0008). Потрібно використовувати квадратні дужки, якщо ви бажаєте отримати збіг з літералом backspace. (Не треба плутати з \b.)
\b +

Відповідає межі слова. Межа слова відповідає позиції де літерному символу не передує або слідує за ним інший літерний символ. Зауважте, що межа слова не включається до збігу. Іншими словами його довжина дорівнює нулю. (Не треба плутати з [\b].)

+ +

Приклади:
+ /\bm/ відповідає 'm' в "moon" ;
+ /oo\b/ не збігається з 'oo' в "moon", тому що за 'oo' йде символ 'n', який є літерним символом;
+ /oon\b/ збігається з 'oon' в "moon", тому що 'oon' є кінцем рядка, тож за ним не йде літерний символ;
+ /\w\b\w/ ніколи не буде мати збігу, тому що за літерним символом ніколи не буде йти не-літерний символ разом з літерним символом.

+ +
+

Примітка: Рушій регулярних виразів JavaScript визначає особливий набір символів що є літерними символами. Будь-який символ не з цього переліка вважається розділовим знаком - межею слова. Цей набір символів є доволі обмеженим: він складається тільки з символів латинської абетки в верхньому та нижньому регістрах, цифр та символу підкресленя. Акцентовані літери, такі як "é" або "ü", несподівано, вважаються розділовими знаками.

+
+
\B +

Відповідає межі не-слова. Цей літерал відповідає позиції де попередній та наступний символи є символами одного типу: Тож обидва символи повині бути літерними, або не-літерними символами. Початок та кінець рядка вважаються не-літерними символами.

+ +

Наприклад, /\B../ відповідає 'oo' в "noonday", та /y\B./ збігається з 'ye' в "possibly yesterday."

+
\cX +

Де X є символом в діапазоні від A до Z. Відповідає керуючим символам в рядку.

+ +

Наприклад, /\cM/ відповідає control-M (U+000D) в рядку.

+
\d +

Відповідає цифровому символу. Еквівалент [0-9].

+ +

Наприклад, /\d/ або /[0-9]/ збігатиметься з '2' в "B2 is the suite number."

+
\D +

Відповідає не-цифровому символу. Еквівалент [^0-9].

+ +

Наприклад, /\D/ або /[^0-9]/ збігатиметься з 'B' в "B2 is the suite number."

+
\fВідповідає символу прогону сторінки (U+000C).
\nВідповідає символу переводу рядка (U+000A).
\rВідповідає символу повернення каретки (U+000D).
\s +

Відповідає одиничному пробільному символу, включаючи пробіл, табуляцію, прогін сторінки, перевод рядка. Еквівалент [ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff].

+ +

Наприклад, /\s\w*/ збігається з ' bar' в "foo bar."

+
\S +

Відповідає одиничному непробільному символу. Еквівалент [^ \f\n\r\t\v\u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff].

+ +

Наприклад, /\S\w*/ відповідає 'foo' в "foo bar."

+
\tВідповідає табуляції (U+0009).
\vВідповідає вертикальній табуляції (U+000B).
\w +

Відповідає будь-якому літерно-цифровому символу включаючи символ підкреслювання. Еквівалент [A-Za-z0-9_].

+ +

Наприклад, /\w/ відповідає 'a' в "apple," '5' в "$5.28," та '3' в "3D."

+
\W +

Відповідає будь-якому не-літерному символу. Еквівалент [^A-Za-z0-9_].

+ +

Наприклад, /\W/ або /[^A-Za-z0-9_]/ відповідає '%' в "50%."

+
\n +

Де n є додатним цілим числом, зворотнє посилання на останій збіг підрядка з n-х відповідних круглих дужок шаблона регулярного виразу (рахуючи від лівої дужки).

+ +

Наприклад, /apple(,)\sorange\1/ відповідає 'apple, orange,' в "apple, orange, cherry, peach."

+
\0Відповідає символу NULL (U+0000). Не використовуйте цей символ разом з іншими цифрами, тому що \0<digits> є вісімковою керуючою послідовністю.
\xhhВідповідає символу з кодом hh (два шістнадцяткові знаки)
\uhhhhВідповідає символу з кодом hhhh (чотири шістнадцяткові знаки).
\u{hhhh}(тільки разом з прапором u) Відповідає символу Юнікод з коом hhhh (шістнадцяткові знаки).
+ +

Екранований ввід користувача буде вважатись літерною послідовністю після застосування регулярного виразу для простої заміни:

+ +
function escapeRegExp(string){
+  return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& - підстановка результату
+}
+ +

Використання дужок

+ +

Дужки навколо будь-якої частини регулярного виразу означають, що ця частина порівнюванного рядка буде збережена. Після цього, ця частина рядка може бути вкликана для повторного використання, більш докладно у {{ web.link("#Using_parenthesized_substring_matches", "Використання збігів підрядків у дужках") }}.

+ +

Наприклад, шаблон /Chapter (\d+)\.\d*/ показує додатково екрановані та спеціальні символи частини шаблону, яку потрібно запамʼятати. Він відповідає точному збігу слова 'Chapter ' за яким йде один чи більше цифрових символів (\d означає будь-який цифровий символ, а + означає 1 чи більше разів), за якими йде десяткова точка (яка сама по собі є спеціальним символом; додавання слеша \ перед точкою дозволяє зробити її звичайним символом '.'), за якою йде будь-яке число, що повторюється від 0 та більше разів (\d означає числовий символ, * означає 0 та більше разів). На додачу, дужки використовуються для того, щоб запамʼятати першу послідовність числових символів.

+ +

Цей шаблон в рядку "Open Chapter 4.3, paragraph 6" знайде числовий символ '4' та запамʼятає його. Шаблон не знайде збігів в "Chapter 3 and 4", тому що рядок не містить точку після '3'.

+ +

Для пошуку відповідності підрядка в дужках без його запамʼятовування. додавайте на початку шаблона в дужках комбінацію ?:. Наприклад, (?:\d+) відповідає одному чи білше числовому символу але без їх запамʼятовування.

+ +

Робота з регулярними виразами

+ +

Регулярні вирази використовуються разом з методами RegExp: test та exec, а також з методами String: mathc, replace, search та split. Ці методи детально описані в  JavaScript reference.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Методи, які використовують регулярні вирази
МетодОпис
{{jsxref("RegExp.exec", "exec")}}Метод RegExp, який виконує пошук віповідностей у рядку. Він повертає список знайдених відповідностей.
{{jsxref("RegExp.test", "test")}}Метод RegExp, який перевіряє, чи рядок містить відповідність регулярному виразу. Повертає true або false.
{{jsxref("String.match", "match")}}Метод String який виконує пошук відповідностей у рядку. Повертає список знайдених відповідностей, або null за невдачі.
{{jsxref("String.search", "search")}}Метод String який перевіряє , чи рядок містить відповідність регулярному виразу. Повертає індекс відповідності або -1 в разі невдачі.
{{jsxref("String.replace", "replace")}}Метод String який виконує пошук відповідності у рядку і заміну знайдених підрядків на заданий рядок заміни.
{{jsxref("String.split", "split")}}Метод String який застосовує регулярний вираз чи рядок-розділювач для розбиття рядку на список підрядків..
+ +

Коли Вам потрібно дізнатися чи міститься шаблон у рядку, використовуйте методи test або search, для детальнішої інформації використовуйте методи exec чи match (виконуються повільніше). Якщо методи exec або match знаходять відповідність вони повертають список і оновлюють властивості пов'язаного об'єкта регулярного виразу, а також передвизначеного об'єкта регулярного виразу, RegExp. В протилежному випадку, метод exec повертає null (який приводиться до false).

+ +

В наступному прикладі, скрипт використовує метод exec для знаходження віповідності у рядку.

+ +
var myRe = /d(b+)d/g;
+var myArray = myRe.exec("cdbbdbsbz");
+
+ +

Якщо у Вас немє потреби мати доступ до властивостей регулярного виразу, альтернативний шлях створення myArray - у такому скрипті:

+ +
var myArray = /d(b+)d/g.exec("cdbbdbsbz");
+
+ +

Ще один варіант цього скрипта, на випадок, якщо Вам потрібно сконструювати регулярний вираз з рядка:

+ +
var myRe = new RegExp("d(b+)d", "g");
+var myArray = myRe.exec("cdbbdbsbz");
+
+ +

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

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Результати виконання регулярного виразу
Об'єктВластивість чи індексОписУ цьому прикладі
myArrayВідповідний рядок та всі запам'ятовані підрядки.["dbbd", "bb"]
indexІндекс відповідності на основі 0 у вхідному рядку.1
inputПочатковий рядок."cdbbdbsbz"
[0]Останні відповідні символи."dbbd"
myRelastIndexІндекс з якого починати наступне порівняння. (Ця властивість встановлюється лише якщо регулярний вираз використовує g опцію, описану в {{ web.link("#Advanced_searching_with_flags", "Advanced Searching With Flags") }}.)5
sourceТекст шаблону. Оновлений під час створення регулярного виразу, а не викионання."d(b+)d"
+ +

Як показано у другій формі цього прикладу, ви можете використовувати регулярні вирази створені через ініціалізатор об'єкта без привласнення їх до змінної. Однак якщо ви робите це, то кожен випадок це регулярний вирах. По цій причині, якщо ви використовуєте цю фору без привласнення до змінної, то у ви не зможете використовувати властивості регулярних виразів. Для прикладу, представте, що у вас є наступний скрипт:

+ +
var myRe = /d(b+)d/g;
+var myArray = myRe.exec("cdbbdbsbz");
+console.log("The value of lastIndex is " + myRe.lastIndex);
+
+// "Значення lastIndex є 5"
+
+ +

Однак, якщо ви маєте цей скрипт:

+ +
var myArray = /d(b+)d/g.exec("cdbbdbsbz");
+console.log("The value of lastIndex is " + /d(b+)d/g.lastIndex);
+
+// "Значення lastIndex є 0"
+
+ +

Випадки /d(b+)d/g  у цих двох виразах є різними об'єктами регулярних виразів, отже мають різні значення для їх lastIndex властивості. Якщо вам треба мати доступ до властивостей регулярного виразу, який був створений через ініціалізатор об'єкту, то спочатку вам треба привласнити його до змінної.

+ +

Використання збігів підрядків у дужках

+ +

Including parentheses in a regular expression pattern causes the corresponding submatch to be remembered. For example, /a(b)c/ matches the characters 'abc' and remembers 'b'. To recall these parenthesized substring matches, use the Array elements [1], ..., [n].

+ +

The number of possible parenthesized substrings is unlimited. The returned array holds all that were found. The following examples illustrate how to use parenthesized substring matches.

+ +

The following script uses the {{jsxref("String.replace", "replace()")}} method to switch the words in the string. For the replacement text, the script uses the $1 and $2 in the replacement to denote the first and second parenthesized substring matches.

+ +
var re = /(\w+)\s(\w+)/;
+var str = "John Smith";
+var newstr = str.replace(re, "$2, $1");
+console.log(newstr);
+
+ +

This prints "Smith, John".

+ +

Advanced searching with flags

+ +

Regular expressions have four optional flags that allow for global and case insensitive searching. These flags can be used separately or together in any order, and are included as part of the regular expression.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Regular expression flags
FlagDescription
gGlobal search.
iCase-insensitive search.
mMulti-line search.
yPerform a "sticky" search that matches starting at the current position in the target string. See {{jsxref("RegExp.sticky", "sticky")}}
+ +

To include a flag with the regular expression, use this syntax:

+ +
var re = /pattern/flags;
+
+ +

or

+ +
var re = new RegExp("pattern", "flags");
+
+ +

Note that the flags are an integral part of a regular expression. They cannot be added or removed later.

+ +

For example, re = /\w+\s/g creates a regular expression that looks for one or more characters followed by a space, and it looks for this combination throughout the string.

+ +
var re = /\w+\s/g;
+var str = "fee fi fo fum";
+var myArray = str.match(re);
+console.log(myArray);
+
+ +

This displays ["fee ", "fi ", "fo "]. In this example, you could replace the line:

+ +
var re = /\w+\s/g;
+
+ +

with:

+ +
var re = new RegExp("\\w+\\s", "g");
+
+ +

and get the same result.

+ +

The m flag is used to specify that a multiline input string should be treated as multiple lines. If the m flag is used, ^ and $ match at the start or end of any line within the input string instead of the start or end of the entire string.

+ +

Examples

+ +

The following examples show some uses of regular expressions.

+ +

Changing the order in an input string

+ +

The following example illustrates the formation of regular expressions and the use of string.split() and string.replace(). It cleans a roughly formatted input string containing names (first name first) separated by blanks, tabs and exactly one semicolon. Finally, it reverses the name order (last name first) and sorts the list.

+ +
// The name string contains multiple spaces and tabs,
+// and may have multiple spaces between first and last names.
+var names = "Harry Trump ;Fred Barney; Helen Rigby ; Bill Abel ; Chris Hand ";
+
+var output = ["---------- Original String\n", names + "\n"];
+
+// Prepare two regular expression patterns and array storage.
+// Split the string into array elements.
+
+// pattern: possible white space then semicolon then possible white space
+var pattern = /\s*;\s*/;
+
+// Break the string into pieces separated by the pattern above and
+// store the pieces in an array called nameList
+var nameList = names.split(pattern);
+
+// new pattern: one or more characters then spaces then characters.
+// Use parentheses to "memorize" portions of the pattern.
+// The memorized portions are referred to later.
+pattern = /(\w+)\s+(\w+)/;
+
+// New array for holding names being processed.
+var bySurnameList = [];
+
+// Display the name array and populate the new array
+// with comma-separated names, last first.
+//
+// The replace method removes anything matching the pattern
+// and replaces it with the memorized string—second memorized portion
+// followed by comma space followed by first memorized portion.
+//
+// The variables $1 and $2 refer to the portions
+// memorized while matching the pattern.
+
+output.push("---------- After Split by Regular Expression");
+
+var i, len;
+for (i = 0, len = nameList.length; i < len; i++){
+  output.push(nameList[i]);
+  bySurnameList[i] = nameList[i].replace(pattern, "$2, $1");
+}
+
+// Display the new array.
+output.push("---------- Names Reversed");
+for (i = 0, len = bySurnameList.length; i < len; i++){
+  output.push(bySurnameList[i]);
+}
+
+// Sort by last name, then display the sorted array.
+bySurnameList.sort();
+output.push("---------- Sorted");
+for (i = 0, len = bySurnameList.length; i < len; i++){
+  output.push(bySurnameList[i]);
+}
+
+output.push("---------- End");
+
+console.log(output.join("\n"));
+
+ +

Using special characters to verify input

+ +

In the following example, the user is expected to enter a phone number. When the user presses the "Check" button, the script checks the validity of the number. If the number is valid (matches the character sequence specified by the regular expression), the script shows a message thanking the user and confirming the number. If the number is invalid, the script informs the user that the phone number is not valid.

+ +

Within non-capturing parentheses (?: , the regular expression looks for three numeric characters \d{3} OR | a left parenthesis \( followed by three digits \d{3}, followed by a close parenthesis \), (end non-capturing parenthesis )), followed by one dash, forward slash, or decimal point and when found, remember the character ([-\/\.]), followed by three digits \d{3}, followed by the remembered match of a dash, forward slash, or decimal point \1, followed by four digits \d{4}.

+ +

The Change event activated when the user presses Enter sets the value of RegExp.input.

+ +
<!DOCTYPE html>
+<html>
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
+    <meta http-equiv="Content-Script-Type" content="text/javascript">
+    <script type="text/javascript">
+      var re = /(?:\d{3}|\(\d{3}\))([-\/\.])\d{3}\1\d{4}/;
+      function testInfo(phoneInput){
+        var OK = re.exec(phoneInput.value);
+        if (!OK)
+          window.alert(phoneInput.value + " isn't a phone number with area code!");
+        else
+          window.alert("Thanks, your phone number is " + OK[0]);
+      }
+    </script>
+  </head>
+  <body>
+    <p>Enter your phone number (with area code) and then click "Check".
+        <br>The expected format is like ###-###-####.</p>
+    <form action="#">
+      <input id="phone"><button onclick="testInfo(document.getElementById('phone'));">Check</button>
+    </form>
+  </body>
+</html>
+
+ +
{{PreviousNext("Web/JavaScript/Guide/Text_formatting", "Web/JavaScript/Guide/Indexed_collections")}}
diff --git a/files/uk/web/javascript/guide/using_promises/index.html b/files/uk/web/javascript/guide/using_promises/index.html new file mode 100644 index 0000000000..d3b986e51a --- /dev/null +++ b/files/uk/web/javascript/guide/using_promises/index.html @@ -0,0 +1,363 @@ +--- +title: Використання промісів +slug: Web/JavaScript/Guide/Using_promises +tags: + - JavaScript + - Promise + - Посібник + - Проміс + - асинхронний +translation_of: Web/JavaScript/Guide/Using_promises +--- +
{{jsSidebar("JavaScript Guide")}}
+ +
{{PreviousNext("Web/JavaScript/Guide/Dokladno_pro_Objectnu_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}
+ +

{{jsxref("Promise")}} (з англ. - "обіцянка", далі - "проміс") - це об'єкт, що відображає кінцеве завершення або невдачу асинхронної операції. Оскільки більшість людей є споживачами раніше створенних промісів, цей посібник спочатку пояснить споживання повернених промісів, а далі пояснить, як їх створювати.

+ +

Проміс, по суті, є поверненим об'єктом, до якого ви прикріплюєте функції зворотного виклику, замість того, щоб передавати їх у функцію.

+ +

Уявіть собі функцію createAudioFileAsync(), яка асинхронно генерує звуковий файл, маючи конфігураційний запис та дві функції зворотного виклику, одна викликається, якщо аудіофайл був успішно створений, а інша викликається, якщо виникає помилка.

+ +

Ось код, який використовує createAudioFileAsync():

+ +
function successCallback(result) {
+  console.log("Аудіофайл створений за адресою: " + result);
+}
+
+function failureCallback(error) {
+  console.log("Під час створення аудіофайлу виникла помилка: " + error);
+}
+
+createAudioFileAsync(audioSettings, successCallback, failureCallback);
+
+ +

Замість цього, сучасні функції повертають проміс, до якого ви можете приєднати функції зворотного виклику:

+ +

Якщо переписати функцію createAudioFileAsync(), щоб вона повертала проміс, її використання буде ось таким простим:

+ +
createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
+ +

Це скорочений запис для:

+ +
const promise = createAudioFileAsync(audioSettings);
+promise.then(successCallback, failureCallback);
+ +

Ми називаємо це асинхронним викликом функції.  Ця конвенція має декілька переваг. Ми дослідимо кожну з них.

+ +

Гарантії

+ +

На відміну від старомодних колбеків, проміс постачається з певними гарантіями:

+ + + +

Однією з величезних переваг промісів є ланцюгування.

+ +

Ланцюгування

+ +

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

+ +

Ось вам магія: функція then() повертає новий проміс, що відрізняється від оригіналу:

+ +
const promise = doSomething();
+const promise2 = promise.then(successCallback, failureCallback);
+
+ +

або

+ +
const promise2 = doSomething().then(successCallback, failureCallback);
+
+ +

Цей другий проміс (promise2) представляє собою завершення не тільки doSomething(), але й successCallback або failureCallback, які ви передали, вони, в свою чергу, можуть бути іншими асинхронними функціями, що повертають проміс. В цьому випадку будь-які функції зворотного виклику, додані до promise2, стають в чергу за промісом, що повертається successCallback чи failureCallback.

+ +

По суті, кожен проміс відображає завершення іншого асинхроннго кроку в ланцюжку.

+ +

В старі часи виконання декількох асинхронних операцій підряд призвело б до класичної піраміди смерті з колбеків:

+ +
doSomething(function(result) {
+  doSomethingElse(result, function(newResult) {
+    doThirdThing(newResult, function(finalResult) {
+      console.log('Ось фінальний результат: ' + finalResult);
+    }, failureCallback);
+  }, failureCallback);
+}, failureCallback);
+
+ +

З сучасними функціями замість цього ми приєднуємо наші функції зворотного виклику до промісів, що повертаються, формуючи ланцюжок промісів.

+ +
doSomething().then(function(result) {
+  return doSomethingElse(result);
+})
+.then(function(newResult) {
+  return doThirdThing(newResult);
+})
+.then(function(finalResult) {
+  console.log('Ось фінальний результат: ' + finalResult);
+})
+.catch(failureCallback);
+
+ +

Аргументи до then є необов'язковими, а catch(failureCallback) - це скорочений запис для  then(null, failureCallback). Ви можете побачити це, виражене за допомогою стрілкових функцій:

+ +
doSomething()
+.then(result => doSomethingElse(result))
+.then(newResult => doThirdThing(newResult))
+.then(finalResult => {
+  console.log(`Ось фінальний результат: ${finalResult}`);
+})
+.catch(failureCallback);
+
+ +

Важливо: Завжди повертайте результати, інакше функції зворотного виклику не перехоплять результат попереднього проміса (у стрілкових функціях () => x є скороченим записом для () => { return x; }).

+ +

Ланцюгування після catch

+ +

Ланцюгувати після невдачі можливо, наприклад, catch є корисним у разі виконання нових операцій навіть після того, як операція у ланцюжку завершилась неуспішно. Дивіться наступний приклад:

+ +
new Promise((resolve, reject) => {
+    console.log('Початковий');
+
+    resolve();
+})
+.then(() => {
+    throw new Error('Щось пішло не так');
+
+    console.log('Зробити це');
+})
+.catch(() => {
+    console.log('Зробити те');
+})
+.then(() => {
+    console.log('Зробити це, що б не відбувалось раніше');
+});
+
+
+ +

Це виведе наступний текст:

+ +
Початковий
+Зробити те
+Зробити це, що б не відбувалось раніше
+
+ +

Зауважте: Текст "Зробити це" не був виведений, тому що помилка "Щось пішло не так" спричинила відхилення.

+ +

Спливання помилок

+ +

Ви, можливо, пригадуєте, що тричі бачили failureCallback раніше, у піраміді смерті, у порівнянні з лише одним викликом наприкінці ланцюжку промісів.

+ +
doSomething()
+.then(result => doSomethingElse(value))
+.then(newResult => doThirdThing(newResult))
+.then(finalResult => console.log(`Ось фінальний результат: ${finalResult}`))
+.catch(failureCallback);
+
+ +

Якщо виникає виняток, переглядач передивляється ланцюжок у пошуках обробників catch або onRejected. Це дуже схоже на модель того, як працює синхронний код:

+ +
try {
+  let result = syncDoSomething();
+  let newResult = syncDoSomethingElse(result);
+  let finalResult = syncDoThirdThing(newResult);
+  console.log(`Ось фінальний результат: ${finalResult}`);
+} catch(error) {
+  failureCallback(error);
+}
+
+ +

Ця симетрія з асинхронним кодом сягає кульмінації в синтаксичному цукрі async/await в ECMAScript 2017:

+ +
async function foo() {
+  try {
+    let result = await doSomething();
+    let newResult = await doSomethingElse(result);
+    let finalResult = await doThirdThing(newResult);
+    console.log(`Ось фінальний результат: ${finalResult}`);
+  } catch(error) {
+    failureCallback(error);
+  }
+}
+
+ +

Він будується на промісах, наприклад, doSomething() - це та сама функція, що й раніше. Ви можете прочитати більше про синтаксис тут.

+ +

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

+ +

Події відхилення промісів

+ +

Коли проміс відхиляється, одна з двох подій надсилається у глобальну область видимості (загалом, це або window, або, при використанні у веб-виконавці, це Worker або інший інтерфейс на базі виконавців). Ці дві події наступні:

+ +
+
rejectionhandled
+
Надсилається, коли проміс відхиляється, після того, як відхилення було оброблене функцією виконавця reject.
+
unhandledrejection
+
Надсилається, коли проміс відхиляється, але немає доступного обробника відхилення.
+
+ +

У обох випадках подія (типу PromiseRejectionEvent) має в якості полів властивість promise, яка вказує відхилений проміс, та властивість reason, яка передає надану причину відхилення проміса.

+ +

Це робить можливою резервну обробку помилок для промісів, а також допомагає відлагоджувати проблеми в управлінні промісами. Ці обробники є глобальними за контекстом, тому усі помилки потраплятимуть в однакові обробники подій, незалежно від джерела.

+ +

Один випадок особливої корисності: при написанні коду для {{Glossary("Node.js")}}, зазвичай, модулі, які ви включаєте у свій проект, можуть мати необроблені відхилені проміси. Вони виводяться у консоль середовищем виконання Node. Ви можете перехопити їх для аналізу та обробити у своєму коді — або просто уникнути захаращення ними виводу даних — додавши обробник події unhandledrejection, ось так:

+ +
window.addEventListener("unhandledrejection", event => {
+  /* Ви можете почати тут, додавши код, щоб дослідити
+     вказаний проміс через event.promise та причину у
+     event.reason */
+
+  event.preventDefault();
+}, false);
+ +

Викликавши метод події preventDefault(), ви кажете середовищу виконання JavaScript не виконувати дію за замовчуванням, коли відхилений проміс лишається необробленим. Ця дія зазвичай містить виведення помилки у консоль, а це якраз випадок для Node.

+ +

В ідеалі, звісно, ви маєте досліджувати відхилені проміси, щоб бути певними, що жоден з них не є насправді помилкою коду, перед тим, як відкидати ці події.

+ +

Створення промісу на основі старого API зі зворотним викликом

+ +

{{jsxref("Promise","Проміс")}} може бути створенний з нуля за допогою свого конструктора. Це необхідно лише для обгортки старих API.

+ +

В ідеальному світі всі асинхронні функції повертали б проміси. На жаль, деякі API досі очікують старомодну передачу функцій зворотного виклику для успіху та/або невдачі. Найбільш очевидним прикладом є функція {{domxref("WindowTimers.setTimeout", "setTimeout()")}} :

+ +
setTimeout(() => saySomething("Пройшло 10 секунд"), 10000);
+
+ +

Змішування старомодних зворотних викликів та промісів є проблематичним. Якщо saySomething завершиться невдачею або міститиме помилку программування, ніщо її не перехопить.

+ +

На щастя, ми можемо обгорнути saySomething у проміс. Найкращою практикою вважається обгортати проблематичні функції на якомога нижчому рівні і вже ніколи не звертатись до них прямо.

+ +
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+wait(10000).then(() => saySomething("10 секунд")).catch(failureCallback);
+
+ +

По суті, конструктор промісу приймає функцію виконання, яка дозволяє вирішити або відхилити проміс вручну. Оскільки setTimeout, насправді, ніколи не завершується невдало, ми пропускаємо функцію відхилення в цьому випадку.

+ +

Композиція

+ +

Методи {{jsxref("Promise.resolve()")}} та {{jsxref("Promise.відхилено", "Promise.reject()")}} є скороченими записами для створення вручну вже вирішених або відхилених промісів відповідно. Інколи це може бути корисно.

+ +

Методи {{jsxref("Promise.all()")}} та {{jsxref("Promise.race()")}} є двома інструментами композиції для паралельного виконання асинхронних операції.

+ +

Ми можемо почати операції паралельно та чекати, доки вони усі не завершаться ось так:

+ +
Promise.all([func1(), func2(), func3()])
+.then(([result1, result2, result3]) => { /* використати result1, result2 та result3 */ });
+ +

Послідовна композиція можлива з використанням певного розумного JavaScript:

+ +
[func1, func2, func3].reduce((p, f) => p.then(f), Promise.resolve())
+.then(result3 => { /* використати result3 */ });
+ +

По суті, ми зменшуємо масив асинхронних функцій до ланцюжка промісів, еквівалентного: Promise.resolve().then(func1).then(func2).then(func3);

+ +

Це можна перетворити на композиційну функцію багаторазового використання, що є типовим у функціональному програмуванні:

+ +
const applyAsync = (acc,val) => acc.then(val);
+const composeAsync = (...funcs) => x => funcs.reduce(applyAsync, Promise.resolve(x));
+ +

Функція composeAsync() прийме будь-яку кількість функцій в якості аргументів і поверне нову функцію, яка приймає початкове значення, що має пройти крізь конвеєр композиції:

+ +
const transformData = composeAsync(func1, func2, func3);
+const result3 = transformData(data);
+
+ +

В ECMAScript 2017 послідовну композицію можна виконати простіше, за допомогою async/await:

+ +
let result;
+for (const f of [func1, func2, func3]) {
+  result = await f(result);
+}
+/* використати останній результат (тобто, result3) */
+ +

Хронометраж

+ +

Щоб уникнути сюрпризів, функції, передані до then(), ніколи не викликатимуться синхронно, навіть для вже вирішеного проміса:

+ +
Promise.resolve().then(() => console.log(2));
+console.log(1); // 1, 2
+
+ +

Замість негайного виконання, передані функції ставляться у чергу мікрозадач. Це означає, що вони виконуються пізніше, коли черга стає порожньою в кінці поточного виконання циклу подій JavaScript, тобто, досить скоро:

+ +
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
+
+wait().then(() => console.log(4));
+Promise.resolve().then(() => console.log(2)).then(() => console.log(3));
+console.log(1); // 1, 2, 3, 4
+
+ +

Вкладеність

+ +

Прості ланцюжки промісів найкраще тримати рівними, без вкладень, оскільки вкладення можуть бути результатом недбалої композиції. Дивіться типові помилки.

+ +

Вкладеність є контролюючою структурою для обмеження області видимості блоків catch. Зокрема, вкладений catch перехоплює лише помилки своєї області видимості та нижче, але не ті помилки, що знаходяться вище у ланцюжку поза вкладеною областю видимості. При правильному використанні це надає більшу точність у виявленні помилок:

+ +
doSomethingCritical()
+.then(result => doSomethingOptional(result)
+  .then(optionalResult => doSomethingExtraNice(optionalResult))
+  .catch(e => {})) // Ігнорувати, якщо не працює щось другорядне; продовжити.
+.then(() => moreCriticalStuff())
+.catch(e => console.error("Критична помилка: " + e.message));
+ +

Зауважте, що необов'язкові кроки тут вкладені, не для відступів, але для передбачливого розташування зовнішніх дужок ( та ) навколо.

+ +

Внутрішній нейтралізуючий блок catch перехоплює помилки тільки від doSomethingOptional() та doSomethingExtraNice(), після чого виконання коду продовжується у moreCriticalStuff(). Що важливо, якщо функція doSomethingCritical() завершується невдало, її помилка перехоплюється тільки кінцевим (зовнішнім) блоком catch.

+ +

Типові помилки

+ +

Ось деякі типові помилки, яких варто остерігатися при складанні ланцюжків промісів. Декілька з цих помилок проявляються у наступному прикладі:

+ +
// Поганий приклад! Помічено 3 помилки!
+
+doSomething().then(function(result) {
+  doSomethingElse(result) // Забули повернути проміс з внутрішнього ланцюжка + непотрібне вкладення
+  .then(newResult => doThirdThing(newResult));
+}).then(() => doFourthThing());
+// Забули завершити ланцюжок блоком catch!
+</pre>
+ +

Перша помилка - не завершувати ланцюжки як слід. Це відбувається, коли ми створюємо новий проміс, але забуваємо його повернути. Як наслідок, ланцюг переривається, чи, скоріше, ми отримуємо два конкуруючі ланцюжки. Це означає, що doFourthThing() не чекатиме на завершення doSomethingElse() чи doThirdThing() і запуститься паралельно з ними, скоріше за все, ненавмисно. В окремих ланцюжках також окремо обробляються помилки, що призводить до неперехоплених помилок.

+ +

Друга помилка - непотрібна вкладеність, що уможливлює першу помилку. Вкладеність також обмежує область видимості внутрішніх обробників помилок, а це — якщо зроблене ненавмисно — може призвести до неперехоплених помилок. Варіантом цього є антишаблон конструювання промісів, який поєднує вкладення з надлишковим використанням конструктора промісів для загортання коду, який вже використовує проміси.

+ +

Третя помилка - забувати завершувати ланцюжки блоком catch. Незавершені ланцюжки промісів призводять до неперехоплених відхилень промісів у більшості переглядачів.

+ +

Гарний практичний підхід - завжди або повертати, або завершувати ланцюжки промісів, і, як тільки ви отримуєте новий проміс, повертати його негайно, щоб вирівняти ланцюжок:

+ +
doSomething()
+.then(function(result) {
+  return doSomethingElse(result);
+})
+.then(newResult => doThirdThing(newResult))
+.then(() => doFourthThing())
+.catch(error => console.error(error));
+ +

Зауважте, що () => x є скороченням для () => { return x; }.

+ +

Тепер ми маємо єдиний, детермінований ланцюжок з правильною обробкою помилок.

+ +

Використання async/await вирішує більшість, якщо не всі ці проблеми — натомість, найпоширенішою помилкою при використанні цього синтаксису є забуте ключове слово await.

+ +

Коли зустрічаються задачі та проміси

+ +

Якщо ви стикаєтеся з ситуаціями, коли у вас є проміси та задачі (такі, як події або зворотні виклики), які запускаються у непередбачуваному порядку, можливо, вам буде корисно скористатись мікрозадачами, щоб перевірити статус або збалансувати проміси, коли створення промісів залежить від певних умов.

+ +

Якщо ви вважаєте, що мікрозадачі могли б вирішити цю проблему, дивіться посібник з мікрозадач, щоб дізнатись, як використовувати метод queueMicrotask(), щоб поставити функцію у чергу як мікрозадачу.

+ +

Дивіться також

+ + + +

{{PreviousNext("Web/JavaScript/Guide/Dokladno_pro_Objectnu_Model", "Web/JavaScript/Guide/Iterators_and_Generators")}}

diff --git a/files/uk/web/javascript/guide/working_with_objects/index.html b/files/uk/web/javascript/guide/working_with_objects/index.html new file mode 100644 index 0000000000..214bae97aa --- /dev/null +++ b/files/uk/web/javascript/guide/working_with_objects/index.html @@ -0,0 +1,490 @@ +--- +title: Робота з об'єктами +slug: Web/JavaScript/Guide/Working_with_Objects +tags: + - JavaScript + - Object + - Документ + - Об'єкт + - Посібник +translation_of: Web/JavaScript/Guide/Working_with_Objects +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Keyed_collections", "Web/JavaScript/Guide/Dokladno_pro_Objectnu_Model")}}
+ +

Мова JavaScript базується на простій, заснованій на об'єктах парадигмі. Об'єкт - це колекція властивостей, а властивість - це асоціація між іменем (або ключем) та значенням. Значення властивості може бути функцією, в цьому випадку властивість відома як метод. На додачу до об'єктів, попередньо визначених у веб-переглядачі, ви можете визначати власні об'єкти. Цей розділ описує, як використовувати об'єкти, властивості, функції та методи, і як створювати власні об'єкти.

+ +

Огляд об'єктів

+ +

Об'єкти у JavaScript, як і у багатьох інших мовах програмування, можна порівняти з об'єктами у реальному житті. Концепію об'єктів у JavaScript можна зрозуміти на прикладі матеріальних об'єктів з реального життя.

+ +

У JavaScript об'єкт - це окрема сутність з властивостями та типом. Порівняємо його, для прикладу, з чашкою. Чашка - це об'єкт з властивостями. Чашка має колір, дизайн, вагу, матеріал, з якого вона зроблена, і т.д. Так само, об'єкти JavaScript можуть мати властивості, які визначають їхні характеристики.

+ +

Об'єкти та властивості

+ +

Об'єкт JavaScript має асоційовані з ним властивості. Властивість об'єкта можна описати як змінну, прикріплену до об'єкта. Властивості об'єкта - це, загалом, те саме, що й звичайні змінні JavaScript, але прикріплені до об'єктів. Властивості об'єкта визначають характеристики об'єкта. Ви звертаєтесь до властивостей об'єкта через просту крапкову нотацію:

+ +
objectName.propertyName
+
+ +

Як усі змінні JavaScript, і ім'я об'єкта (яке може бути звичайною змінною), і ім'я властивості чутливі до регістру. Ви можете визначити властивість, присвоївши їй значення. Наприклад, створимо об'єкт на ім'я myCar (моя машина) та дамо йому властивості make (виробник), model (модель) та year (рік) ось так:

+ +
var myCar = new Object();
+myCar.make = 'Ford';
+myCar.model = 'Mustang';
+myCar.year = 1969;
+
+ +

Наведений приклад також міг бути написаний за допомогою об'єктного ініціалізатора, який є списком з нуля чи більше розділених комами пар імен властивостей об'єкта та асоційованих з ними значень, записаний у фігурних дужках ({}):

+ +
var myCar = {
+    make: 'Ford',
+    model: 'Mustang',
+    year: 1969
+};
+
+ +

Неприсвоєні властивості об'єкта мають значення {{jsxref("undefined")}} (а не {{jsxref("null")}}).

+ +
myCar.color; // undefined
+ +

До властивостей об'єктів JavaScript також можна звертатись чи присвоювати їх за допомогою дужкової нотації (щоб дізнатись більше, дивіться доступ до властивостей). Об'єкти іноді називають асоціативними масивами, оскільки кожна властивість асоціюється з рядковим значенням, яке можна використати для доступу до неї. Отже, для прикладу, ви можете звертатись до властивостей об'єкта myCar наступним чином:

+ +
myCar['make'] = 'Ford';
+myCar['model'] = 'Mustang';
+myCar['year'] = 1969;
+
+ +

Ім'я властивості об'єкта може бути будь-яким дозволеним рядком JavaScript чи будь-чим, що можна привести до рядка, в тому числі порожній рядок. Однак, будь-яке ім'я властивості, яке не є дозволеним ідентифікатором JavaScript (наприклад, ім'я властивості, що містить пробіл чи дефіс, або починається з цифри) доступне тільки через позначення у квадратних дужках. Ця нотація також дуже корисна, коли імена властивостей мають бути динамічно визначені (коли ім'я властивості не визначене до початку виконання). Приклади наступні:

+ +
// створюємо одночасно чотири змінні, розділені комами,
+// та присвоюємо їм значення
+var myObj = new Object(),
+    str = 'myString',
+    rand = Math.random(),
+    obj = new Object();
+
+myObj.type              = 'крапковий синтаксис';
+myObj['date created']   = 'рядок з пробілом';
+myObj[str]              = 'рядкове значення';
+myObj[rand]             = 'випадкове число';
+myObj[obj]              = 'об\'єкт';
+myObj['']               = 'навіть порожній рядок';
+
+console.log(myObj);
+
+ +

Будь ласка, зауважте, що усі ключі, позначені у квадратних дужках, перетворюються на рядки, якщо тільки вони не є символами, оскільки імена властивостей (ключів) об'єктів JavaScript можуть бути тільки рядками або символами (в якийсь момент також будуть додані приватні імена, з розвитком пропозиції щодо полів класу, але вони не використовуватимуться у формі []). Наприклад, у наведеному вище коді, коли ключ obj додається до об'єкта myObj, JavaScript викличе метод {{jsxref("Object.toString", "obj.toString()")}} та використає отриманий рядок як новий ключ.

+ +

Ви також можете звернутись до властивості, використавши рядкове значення, що зберігається у змінній:

+ +
var propertyName = 'make';
+myCar[propertyName] = 'Ford';
+
+propertyName = 'model';
+myCar[propertyName] = 'Mustang';
+
+ +

Ви можете використати дужкову нотацію з циклом for...in для перебору усіх перелічуваних властивостей об'єкта. Для ілюстрації того, як це працює, наступна функція відображає властивості об'єкта, коли ви передаєте об'єкт та ім'я об'єкта в якості аргументів у функцію:

+ +
function showProps(obj, objName) {
+  var result = ``;
+  for (var i in obj) {
+    // obj.hasOwnProperty() відфільтровує властивості від ланцюга прототипів об'єкта
+    if (obj.hasOwnProperty(i)) {
+      result += `${objName}.${i} = ${obj[i]}\n`;
+    }
+  }
+  return result;
+}
+
+ +

Отже, виклик функції showProps(myCar, "myCar") поверне наступне:

+ +
myCar.make = Ford
+myCar.model = Mustang
+myCar.year = 1969
+ +

Перелік властивостей об'єкта

+ +

Починаючи з ECMAScript 5, існують три вбудовані методи перелічити / продивитись властивості об'єкта:

+ + + +

До ECMAScript 5 не існувало вбудованого способу перелічити усі властивості об'єкта. Однак, цього можна досягти наступною функцією:

+ +
function listAllProperties(o) {
+	var objectToInspect;
+	var result = [];
+
+	for(objectToInspect = o; objectToInspect !== null;
+           objectToInspect = Object.getPrototypeOf(objectToInspect)) {
+        result = result.concat(
+            Object.getOwnPropertyNames(objectToInspect)
+        );
+    }
+
+	return result;
+}
+
+ +

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

+ +

Створення нових об'єктів

+ +

JavaScript має чимало попередньо визначених об'єктів. На додачу, ви можете створювати свої власні об'єкти. Ви можете створити об'єкт за допомогою об'єктного ініціалізатора. Або ви можете спочатку створити функцію-конструктор, після чого створювати об'єкти, використовуючи оператор new.

+ +

Використання об'єктних ініціалізаторів

+ +

На додачу до створення об'єктів за допомогою функції-конструктора, ви можете створювати об'єкти, використовуючи об'єктний ініціалізатор. Використання об'єктних ініціалізаторів іноді називають створенням об'єктів літеральною нотацією. "Об'єктний ініціалізатор" відповідає термінології, що використовується у мові C++.

+ +

Синтаксис об'єкта, що використовує об'єктний ініціалізатор, наступний:

+ +
var obj = { property_1:   value_1,   // property_# може бути ідентифікатором...
+            2:            value_2,   // або числом...
+            // ...,
+            'property n': value_n }; // або рядком
+
+ +

де obj - ім'я нового об'єкта, кожне ім'я property_i є ідентифікатором (або числом, або рядковим літералом), а кожне значення value_i є виразом, чиє значення присвоюється властивості property_i. Змінна obj та присвоєння є необов'язковими; якщо вам непотрібно звертатись до цього об'єкта будь-де, вам непотрібно присвоювати його змінній. (Зауважте, що вам може знадобитись загорнути об'єктний літерал у круглі дужки, якщо об'єкт з'являється там, де очікується інструкція, щоб літерал не був прийнятий за блочну інструкцію.)

+ +

Об'єктні ініціалізатори є виразами, а кожний об'єктний ініціалізатор створює новий об'єкт, коли виконується інструкція, де він знаходиться. Ідентичні об'єктні ініціалізатори створюють окремі об'єкти, які не вважатимуться рівними. Об'єкти створюються так, ніби відбувся виклик new Object(); тобто, об'єкти, створені об'єктними літералами, є екземплярами Object.

+ +

Наступна інструкція створює об'єкт та присвоює його змінній x тільки за умови, що вираз cond є правдивим:

+ +
if (cond) var x = {greeting: 'привітик'};
+
+ +

Наступний приклад створює об'єкт myHonda з трьома властивостями. Зауважте, що властивість engine також є об'єктом зі своїми властивостями.

+ +
var myHonda = {color: 'червоний', wheels: 4, engine: {cylinders: 4, size: 2.2}};
+
+ +

Ви також можете використовувати об'єктні ініціалізатори для створення масивів. Дивіться масивні літерали.

+ +

Використання функції-конструктора

+ +

Також ви можете створити об'єкт, виконавши ці два кроки:

+ +
    +
  1. Визначити тип об'єкта, написавши функцію-конструктор. Загальноприйнято, і на це є причини, писати їх з великої літери.
  2. +
  3. Створити екземпляр об'єкта за допомогою new.
  4. +
+ +

Щоб визначити тип об'єкта, створіть функцю для типу об'єкта, яка визначає його ім'я, властивості та методи. Наприклад, припустимо, ви хочете створити тип об'єкта для автомобілів. Ви хочете, щоб цей тип об'єкта називався Car, і ви хочете, щоб він мав властивості для виробника, моделі та року. Щоб це зробити, ви б написали наступну функцію:

+ +
function Car(make, model, year) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+}
+
+ +

Зверніть увагу на використання this для присвоєння значень властивостям об'єкта на основі значень, переданих у функцію.

+ +

Тепер ви можете створити об'єкт на ім'я mycar наступним чином:

+ +
var mycar = new Car('Eagle', 'Talon TSi', 1993);
+
+ +

Ця інструкція створює об'єкт mycar та присвоює вказані значення його властивостям. Тоді значенням mycar.make є рядок "Eagle", mycar.year дорівнює цілому число 1993 і т.д.

+ +

Ви можете створити довільне число об'єктів Car викликами new. Наприклад,

+ +
var kenscar = new Car('Nissan', '300ZX', 1992);
+var vpgscar = new Car('Mazda', 'Miata', 1990);
+
+ +

Об'єкт може мати властивість, яка сама є іншим об'єктом. Наприклад, припустимо, ви визначаєте об'єкт person (людина) наступним чином:

+ +
function Person(name, age, sex) {
+  this.name = name;
+  this.age = age;
+  this.sex = sex;
+}
+
+ +

і далі створюєте два екземпляра об'єкта person наступним чином:

+ +
var rand = new Person('Rand McKinnon', 33, 'M');
+var ken = new Person('Ken Jones', 39, 'M');
+
+ +

Тоді ви можете переписати визначення Car, щоб включити властивість owner (власник), яка приймає об'єкт person ось так:

+ +
function Car(make, model, year, owner) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+  this.owner = owner;
+}
+
+ +

Тепер, щоб створити нові об'єкти, ви зробите наступне:

+ +
var car1 = new Car('Eagle', 'Talon TSi', 1993, rand);
+var car2 = new Car('Nissan', '300ZX', 1992, ken);
+
+ +

Зверніть увагу, що, замість передачі літералу рядка чи цілого числа під час створення нових об'єктів, наведені вище інструкції передають об'єкти rand та ken в якості значень власників. Тепер, якщо вам потрібно дізнатись ім'я власника car2, ви можете звернутись до наступної властивості:

+ +
car2.owner.name
+
+ +

Зауважте, що ви завжди можете додати властивість до попередньо визначеного об'єкта. Наприклад, інструкція

+ +
car1.color = 'чорний';
+
+ +

додає властивість color (колір) до car1, та присвоює їй значення "чорний." Однак, це не впливає на всі інші об'єкти. Щоб додати нову властивість до усіх об'єктів того самого типу, ви маєте додати властивість до визначення типу об'єкта Car.

+ +

Використання методу Object.create

+ +

Об'єкти також можна створювати методом {{jsxref("Object.create()")}}. Цей метод може бути дуже корисним, тому що дозволяє обирати прототип для об'єкта, який ви хочете створити, без необхідності визначати функцію-конструктор.

+ +
// Властивості об'єкта Animal (тварина) та інкапсуляція методу
+var Animal = {
+  type: 'Безхребетні', // Значення властивості за замовчуванням
+  displayType: function() {  // Метод, що виводитиме тип тварини
+    console.log(this.type);
+  }
+};
+
+// Створити нову тварину з назвою animal1
+var animal1 = Object.create(Animal);
+animal1.displayType(); // виведе: Безхребетні
+
+// Створити нову тварину з назвою fish (риба)
+var fish = Object.create(Animal);
+fish.type = 'Риби';
+fish.displayType(); // виведе: Риби
+ +

Наслідування

+ +

Усі об'єкти у JavaScript успадковуються від принаймні одного іншого об'єкта. Об'єкт, від якого наслідується інший об'єкт, відомий як прототип, а успадковані властивості можна знайти у об'єкті конструктора prototype. Щоб дізнатись більше, дивіться Наслідування та ланцюжок прототипів.

+ +

Індексування властивостей об'єкта

+ +

Ви можете звернутись до властивості об'єкта або за іменем властивості, або за його оригінальним індексом. Якщо ви з самого початку визначили властивість за іменем, ви завжди маєте звертатись до неї за іменем, а якщо ви визначили властивість за індексом, ви завжди маєте звертатись до неї за індексом.

+ +

Це обмеження працює, коли ви створюєте об'єкт та його властивості функцією-конструктором (як ми робили раніше з типом об'єкта Car) та коли ви явно визначаєте окремі властивості (наприклад, myCar.color = "червоний"). Якщо ви початково визначили властивість об'єкта з індексом, як от myCar[5] = "25 mpg", ви далі звертаєтесь до властивості лише у вигляді myCar[5].

+ +

Винятком з цього правила є подібний до масиву об'єкт з HTML, такий як подібний до масиву об'єкт forms. Ви завжди можете посилатись на об'єкти у цих подібних до масивів об'єктах або за їхнім порядковим номером (в залежності від їхнього розташування у документі), або за іменем (якщо воно визначене). Наприклад, якщо другий тег <FORM> у документі має атрибут NAME, що дорівнює "myForm", ви можете звернутись до форми document.forms[1], або document.forms["myForm"], або document.forms.myForm.

+ +

Визначення властивостей для типу об'єкта

+ +

Ви можете додати властивість до попередньо визначеного типу об'єкта за допомогою властивості prototype. Це визначає властивість, спільну для усіх об'єктів вказаного типу, а не лише для одного екземпляру об'єкта. Наступний код додає властивість color (колір) до усіх об'єктів типу Car (автомобіль), після чого присвоює значення властивості color об'єкта car1.

+ +
Car.prototype.color = null;
+car1.color = 'чорний';
+
+ +

Щоб дізнатись більше, дивіться властивість prototype об'єкта Function у довіднику JavaScript.

+ +

Визначення методів

+ +

Метод - це функція, асоційована з об'єктом, або, простіше кажучи, метод - це властивість об'єкта, яка є функцією. Методи визначаються так само, як звичайні функції, за винятком того, що вони мають бути асоційовані з властивістю об'єкта. Дивіться більше подробиць у визначенні методів. Приклад наступний:

+ +
objectName.methodname = functionName;
+
+var myObj = {
+  myMethod: function(params) {
+    // ...зробити щось
+  }
+
+  // ТАКЕ ТЕЖ ПРАЦЮЄ
+
+  myOtherMethod(params) {
+    // ...зробити щось інше
+  }
+};
+
+ +

де objectName - це існуючий об'єкт, methodname - це ім'я, яке ви присвоюєте методу, а functionName - це ім'я функції.

+ +

Далі ви можете викликати метод у контексті об'єкта наступним чином:

+ +
object.methodname(params);
+
+ +

Ви можете визначати методи для типу об'єкта, додавши визначення методів у конструктор об'єкта. Ви можете визначити функцію, що буде форматувати та відображати властивості попередньо визначених об'єктів Car; наприклад,

+ +
function displayCar() {
+  var result = `Чудовий автомобіль ${this.year} ${this.make} ${this.model}`;
+  pretty_print(result);
+}
+
+ +

де pretty_print - функція, що відображатиме горизонтальне правило та рядок. Зверніть увагу на використання this для посилання на об'єкт, до якого належить метод.

+ +

Ви можете зробити цю функцію методом Car, додавши інструкцію

+ +
this.displayCar = displayCar;
+
+ +

до визначення об'єкта. Отже, повне визначення Car виглядатиме так

+ +
function Car(make, model, year, owner) {
+  this.make = make;
+  this.model = model;
+  this.year = year;
+  this.owner = owner;
+  this.displayCar = displayCar;
+}
+
+ +

Тоді ви можете викликати метод displayCar для кожного об'єкта наступним чином:

+ +
car1.displayCar();
+car2.displayCar();
+
+ +

Використання this у посиланнях на об'єкт

+ +

JavaScript має спеціальне ключове слово this, яке ви можете використати всередині метода, щоб вказати на поточний об'єкт. Наприклад, припустимо, ви маєте 2 об'єкта, Manager та Intern. Кожен об'єкт має свої власні name (ім'я), age (вік) та job (роботу). У функції sayHi(), зверніть увагу, є this.name. Додані до 2-х об'єктів, вони можуть бути викликані та повернуть 'Привіт, мене звуть', а далі додають значення name з цього конкретного об'єкта. Як показано нижче. 

+ +
const Manager = {
+  name: "Джон",
+  age: 27,
+  job: "Програміст"
+}
+const Intern= {
+  name: "Бен",
+  age: 21,
+  job: "Програміст-інтерн"
+}
+
+function sayHi() {
+    console.log('Привіт, мене звуть', this.name)
+}
+
+// додаємо функцію sayHi до обох об'єктів
+Manager.sayHi = sayHi;
+Intern.sayHi = sayHi;
+
+Manager.sayHi() // Привіт, мене звуть Джон
+Intern.sayHi() // Привіт, мене звуть Бен
+
+ +

this посилається на об'єкт, в якому знаходиться. Ви можете створити нову функцію під назвою howOldAmI(), яка виводить повідомлення про те, скільки цій людині років. 

+ +
function howOldAmI (){
+  console.log('Мені ' + this.age + ' років.')
+}
+Manager.howOldAmI = howOldAmI;
+Manager.howOldAmI() // Мені 27 років.
+
+ +

Визначення гетерів та сетерів

+ +

Гетер - це метод, який отримує значення конкретної властивості. Сетер - це метод, який присвоює значення конкретній властивості. Ви можете визначати гетери та сетери на будь-якому існуючому базовому об'єкті чи об'єкті, створеному користувачем, якщо він підтримує додавання нових властивостей. 

+ +

Гетери та сетери можуть бути або

+ + + +

При визначенні гетерів та сетерів за допомогою об'єктних ініціалізаторів вам потрібно лише додати перед методом-гетером get, а перед методом-сетером set. Звісно, гетер не повинен очікувати на параметри, а сетер очікує рівно на один параметер (нове значення, яке треба присвоїти). Наприклад:

+ +
var o = {
+  a: 7,
+  get b() {
+    return this.a + 1;
+  },
+  set c(x) {
+    this.a = x / 2;
+  }
+};
+
+console.log(o.a); // 7
+console.log(o.b); // 8 <-- В цьому місці запускається метод get b().
+o.c = 50;         //   <-- В цьому місці запускається метод set c(x).
+console.log(o.a); // 25
+
+ +

Властивості об'єкта o наступні:

+ + + +

Будь ласка, зауважте, що імена функцій гетерів та сетерів, визначені у об'єктному літералі за допомогою "[gs]et властивість()" (на відміну від __define[GS]etter__ ), не є іменами самих гетерів, хоча синтаксис [gs]et propertyName(){ } і міг ввести вас в оману.

+ +

Гетери та сетери також можуть бути додані до об'єкта в будь-який момент після створення за допомогою методу Object.defineProperties. Першим параметром цього методу є об'єкт, на якому ви хочете визначити гетер чи сетер. Другим параметром є об'єкт, чиї імена властивостей є іменами гетерів чи сетерів і чиї значення властивостей є об'єктами для визначення функцій гетерів чи сетерів. Ось приклад, який визначає такі самі гетер та сетер, які використовувались у попередньому прикладі:

+ +
var o = { a: 0 };
+
+Object.defineProperties(o, {
+    'b': { get: function() { return this.a + 1; } },
+    'c': { set: function(x) { this.a = x / 2; } }
+});
+
+o.c = 10; // Запускає сетер, який присвоює 10 / 2 (5) властивості 'a'
+console.log(o.b); // Запускає гетер, який видає a + 1, тобто 6
+
+ +

Яку з двох форм обирати, залежить від вашого стилю програмування та наявної задачі. Якщо ви вже користуєтесь об'єктним ініціалізатором при визначенні прототипу, ви, скоріше за все, обиратимете першу форму. Ця форма є більш компактною та природньою. Однак, якщо ви додаєте гетери та сетери пізніше — оскільки не писали прототип чи окремий об'єкт — тоді друга форма є єдино можливою. Друга форма, можливо, найкраще відображає динамічну природу JavaScript — але вона може зробити код важким для читання та розуміння.

+ +

Видалення властивостей

+ +

Ви можете видалити неуспадковані властивості оператором delete. Наступний код демонструє, як прибрати властивість.

+ +
// Створює новий об'єкт, myobj, з двома властивостями, a та b.
+var myobj = new Object;
+myobj.a = 5;
+myobj.b = 12;
+
+// Прибирає властивість a, залишивши у myobj лише властивість b.
+delete myobj.a;
+console.log ('a' in myobj); // виведе: "false"
+
+ +

Ви також можете використати delete, щоб видалити глобальну змінну, якщо ключове слово var не використовувалось для оголошення змінної:

+ +
g = 17;
+delete g;
+
+ +

Порівняння об'єктів

+ +

У JavaScript об'єкти належать до типу посилань. Два окремі об'єкти ніколи не дорівнюють один одному, навіть якщо мають однакові властивості. Лише порівняння об'єкта з самим собою поверне true.

+ +
// Дві змінні, два окремих об'єкти з однаковими властивостями
+var fruit = {name: 'яблуко'};
+var fruitbear = {name: 'яблуко'};
+
+fruit == fruitbear; // вертає false
+fruit === fruitbear; // вертає false
+ +
// Дві змінні, один об'єкт
+var fruit = {name: 'яблуко'};
+var fruitbear = fruit;  // Присвоїти fruitbear посилання на об'єкт fruit
+
+// Тут fruit та fruitbear вказують на один об'єкт
+fruit == fruitbear; // вертає true
+fruit === fruitbear; // вертає true
+
+fruit.name = 'виноград';
+console.log(fruitbear); // output: { name: "виноград" }, замість { name: "яблуко" }
+
+ +

Щоб дізнатись більше щодо операторів порівняння, дивіться Оператори порівняння.

+ +

Див. також

+ + + +

{{PreviousNext("Web/JavaScript/Guide/Regular_Expressions", "Web/JavaScript/Guide/Dokladno_pro_Objectnu_Model")}}

diff --git "a/files/uk/web/javascript/guide/\320\262\320\270\321\200\320\260\320\267\320\270_\321\202\320\260_\320\276\320\277\320\265\321\200\320\260\321\202\320\276\321\200\320\270/index.html" "b/files/uk/web/javascript/guide/\320\262\320\270\321\200\320\260\320\267\320\270_\321\202\320\260_\320\276\320\277\320\265\321\200\320\260\321\202\320\276\321\200\320\270/index.html" new file mode 100644 index 0000000000..fdfbc0659b --- /dev/null +++ "b/files/uk/web/javascript/guide/\320\262\320\270\321\200\320\260\320\267\320\270_\321\202\320\260_\320\276\320\277\320\265\321\200\320\260\321\202\320\276\321\200\320\270/index.html" @@ -0,0 +1,925 @@ +--- +title: Вирази та оператори +slug: Web/JavaScript/Guide/Вирази_та_оператори +tags: + - JavaScript + - Оператори + - Посібник + - вирази +translation_of: Web/JavaScript/Guide/Expressions_and_Operators +--- +
{{jsSidebar("JavaScript Guide")}} {{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}
+ +

Цей розділ описує вирази та оператори JavaScript, такі як присвоювання, порівняння, арифметичні оператори, бітові, логічні, рядкові, тернарний та інші.

+ +

Повний та детальний список операторів та виразів також доступний за посиланням.

+ +

Оператори

+ +

JavaScript має наступні типи операторів. Ця секція описує оператори, а також містить інформацію щодо їхніх пріоритетів.

+ + + +

JavaScript має як бінарні, так і унарні оператори, а також один особливий тернарний оператор - умовний оператор. Бінарному оператору потрібні два операнди - один перед оператором, інший після оператора:

+ +
операнд1 оператор операнд2
+
+ +

Наприклад, 3+4 чи x*y.

+ +

Унарний оператор потребує лише одного операнду до чи після оператора:

+ +
оператор операнд
+
+ +

чи

+ +
операнд оператор
+
+ +

Наприклад, x++ чи ++x.

+ +

Оператори присвоєння

+ +

Оператор присвоєння присвоює своєму лівому операнду значення на підставі значення правого операнда. Простим оператором присвоєння є оператор дорівнює (=), який присвоює значення свого правого операнда лівому операнду. Таким чином, x = y присвоює значення змінної y змінній x.

+ +

Також існують складені оператори присвоєння, які є скороченнями для операцій, перелічених у наступній таблиці:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Складені оператори присвоювання
НазваОператор скороченого записуЗначення
Присвоєнняx = yx = y
Присвоєння з додаваннямx += yx = x + y
Присвоєння з відніманнямx -= yx = x - y
Присвоєння з множеннямx *= yx = x * y
Присвоєння з діленнямx /= yx = x / y
Присвоєння остачіx %= yx = x % y
Присвоєння з піднесенням до степеня{{experimental_inline}}x **= yx = x ** y
Присвоєння з лівим зсувомx <<= yx = x << y
Присвоєння з правим зсувомx >>= yx = x >> y
Присвоєння з беззнаковим правим зсувомx >>>= yx = x >>> y
Присвоєння з побітовим Іx &= yx = x & y
Присвоєння з виключним побітовим АБОx ^= yx = x ^ y
Присвоєння з побітовим АБОx |= yx = x | y
+ +

Деструктуризація

+ +

Для більш складних присвоювань використовується синтаксис деструктуризації. Це вираз JavaScript, який надає можливість витягувати дані з масивів та об'єктів, використовуючи синтаксис, що віддзеркалює конструкцію масивів та об'єктних літералів. 

+ +
var foo = ['один', 'два', 'три'];
+
+// без деструктуризації
+var one   = foo[0];
+var two   = foo[1];
+var three = foo[2];
+
+// із деструктуризацією
+var [one, two, three] = foo;
+
+ +

Оператори порівняння

+ +

Оператор порівняння порівнює свої операнди та повертає логічне значення, базуючись на істинності порівняння. Операнди можуть бути числовими, рядковими, логічними значеннями або об'єктами. Рядки порівнюються згідно стандартного лексикографічного порядку, з використанням значень Unicode. У більшості випадків, якщо два операнди не належать до одного типу, JavaScript намагається привести їх до належного для порівняння типу. Зазвичай це призводить до числового порівняння операндів. Єдиними винятками у конвертації типів під час порівняння є оператори === та !==, які виконують перевірку на строгу рівність та строгу нерівність. Ці оператори не намагаються перед перевіркою на рівність привести операнди до спільного типу. Наступна таблиця наводить оператори порівняння у контексті цього фрагменту коду:

+ +
var var1 = 3;
+var var2 = 4;
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Оператори порівняння
ОператорОписПриклади, які повертають true
Рівність (==)Повертає true, якщо оператори рівні.3 == var1 +

"3" == var1

+ 3 == '3'
Нерівність (!=)Повертає true, якщо оператори нерівні.var1 != 4
+ var2 != "3"
Строга рівність (===)Повертає true якщо оператори рівні та належать до одного типу. Дивіться також {{jsxref("Object.is")}} та однаковість у JS.3 === var1
Строга нерівність (!==)Повертає true, якщо оператори належать до одного типу, але нерівні, або належать до різних типів.var1 !== "3"
+ 3 !== '3'
Більше ніж (>)Повертає true, якщо лівий операнд більший за правий.var2 > var1
+ "12" > 2
Більше чи дорівнює (>=)Повертає true, якщо значення лівого операнда більше або дорівнює значенню правого операнда.var2 >= var1
+ var1 >= 3
Менше ніж (<)Повертає true, якщо лівий операнд менший за правий.var1 < var2
+ "2" < 12
Менше чи дорівнює (<=)Повертає true, якщо значення лівого операнда менше або дорівнює значенню правого операнда.var1 <= var2
+ var2 <= 5
+ +
+

Заувага: (=>) не оператор, а позначення для стрілкових функцій.

+
+ +

Арифметичні оператори

+ +

Арифметичний оператор приймає числові значення (літерали чи змінні) в якості операндів та повертає єдине числове значення. Стандартними арифметичними операторами є додавання (+), віднімання (-), множення (*) та ділення (/). Ці оператори працюють так само, як і в більшості інших мов програмування при використанні з числами з рухомою комою (зокрема, зауважте, що ділення на нуль повертає {{jsxref("Infinity")}}). Наприклад:

+ +
1 / 2; // 0.5
+1 / 2 == 1.0 / 2.0; // це дорівнює true
+
+ +

На додачу до стандартних арифметичних операцій (+, -, * /), JavaScript надає арифметичні операції, перечислені у наведеній нижче таблиці:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Арифметичні оператори
ОператорОписПриклад
Остача (%)Бінарний оператор. Повертає цілочисельну остачу від ділення двох операндів.12 % 5 повертає 2.
Інкремент (++)Унарний оператор. Додає до операнда одиницю. Якщо використовується як префіксний оператор (++x), повертає значення операнда після додавання одиниці; якщо використовується як постфіксний оператор (x++), повертає значення операнда перед додаванням одиниці.Якщо x дорівнює 3, тоді ++x присвоює x значення 4 та повертає 4, в той час, як x++ повертає 3 і лише тоді присвоює x значення 4.
Декремент (--)Унарний оператор. Віднімає одиницю від свого операнда. Повернене значення аналогічне поверненому значенню оператора інкременту.Якщо x дорівнює 3, тоді --x присвоює x значення 2 та повертає 2, в той час, як x-- повертає 3 і тільки тоді присвоює x значення 2.
Унарний мінус (-)Унарний оператор. Повертає операнд з протилежним знаком.Якщо x дорівнює 3, то -x повертає -3.
Унарний плюс (+)Унарний оператор. Намагається перетворити операнд на число, якщо він не є числом.+"3" повертає 3.
+ +true повертає 1.
Піднесення до степеня (**) {{experimental_inline}}Підносить основу степеня до показника степеня, тобто, основапоказник2 ** 3 повертає 8.
+ 10 ** -1 повертає 0.1.
+ +

Бітові оператори

+ +

Бітовий оператор опрацьовує свої операнди як послідовність 32-х бітів (нулів та одиниць), а не як десяткові, шістнадцяткові або вісімкові числа. Наприклад, десяткове число дев'ять має бітове представлення 1001. Бітові оператори виконують операції над цими бітовими представленнями, але повертають стандартні числові значення JavaScript.

+ +

Наступна таблиця наводить перелік бітових операторів JavaScript.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Бітові оператори
ОператорЗастосуванняОпис
Побітове І (AND)a & bПовертає одиницю на кожній позиції, де відповідні біти обох операндів дорівнюють одиницям.
Побітове АБО (OR)a | bПовертає нуль на кожній позиції, де відповідні біти обох операндів дорівнюють нулям.
Виключне побітове АБО (XOR)a ^ bПовертає нуль на кожній позиції, де відповідні біти однакові.
+ [Повертає один на кожній позиції, де відповідні біти мають різні значення.]
Побітове НЕ (NOT)~ aВиконує інверсію бітів операнду.
Лівий зсувa << bЗсуває a у двійковому представленні на b бітів ліворуч, заповнюючи позиції справа нулями.
Правий зсув з розширенням знакуa >> bЗсуває a у двійковому представленні на b бітів праворуч, відкидаючи зсунуті біти.
Правий зсув із заповненням нулямиa >>> bЗсуває a у двійковому представленні на b бітів праворуч, відкидаючи зсунуті біти та заповнюючи позиції зліва нулями.
+ +

Побітові логічні оператори

+ +

Концептуально побітові логічні оператори працюють наступним чином:

+ + + +

Наприклад, бінарним представленням числа дев'ять є 1001, а бінарним представленням п'ятнадцяти є 1111. Отже, коли бітові оператори застосовуються до цих величин, результати будуть наступні:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Приклади бітових операторів
ВиразРезультатДвійковий опис
15 & 991111 & 1001 = 1001
15 | 9151111 | 1001 = 1111
15 ^ 961111 ^ 1001 = 0110
~15-16~00000000...00001111 = 11111111...11110000
~9-10~00000000...00001001 = 11111111...11110110
+ +

Зауважте, що усі 32 біти інвертуються побітовим оператором НЕ, і що значення, в яких найстарший (перший зліва) біт дорівнює 1, відображають від'ємні числа (формат доповняльного коду).

+ +

Оператори бітового зсуву

+ +

Оператори бітового зсуву приймають два операнди: перший є величиною, в якій треба виконати зсув, а другий вказує кількість бітових позицій для зсуву. Напрямок операції зсуву контролюється застосованим оператором.

+ +

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

+ +

Оператори зсуву наведені у наступній таблиці.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Оператори бітового зсуву
ОператорОписПриклад
Лівий зсув
+ (<<)
Цей оператор виконує зсув першого операнду на вказану кількість бітів ліворуч. Надлишкові біти, зсунуті ліворуч, відкидаються. Біти, додані справа, заповнюються нулями.9<<2 вертає 36, тому що число 1001, зсунуте на 2 біти ліворуч, стає 100100, тобто, 36.
Правий зсув з розширенням знаку (>>) +

Цей оператор виконує зсув першого операнду на вказану кількість бітів праворуч. Надлишкові біти, зсунуті праворуч, відкидаються. Біти, додані зліва, заповнюються значенням старшого біта.

+
9>>2 вертає 2, тому що число 1001, зсунуте на 2 біти праворуч, стає 10, тобто 2. Аналогічно, -9>>2 вертає -3,  тому що знак зберігається.
Правий зсув із заповненням нулями(>>>) +

Цей оператор виконує зсув першого операнду на вказану кількість бітів праворуч. Надлишкові біти, зсунуті праворуч, відкидаються. Біти, додані зліва, заповнюються нулями.

+
19>>>2 вертає 4, тому що число 10011, зсунуте на 2 бітів праворуч, стає 100, тобто 4. Для невід'ємних чисел, правий зсув із заповненням нулями та правий зсув з розширенням знаку дають однаковий результат.
+ +

Логічні оператори

+ +

Логічні оператори застосовуються до булевих (логічних) значень; в цьому випадку вони повертають значення типу Boolean. Однак, оператори && та || насправді повертають значення одного з заданих операндів, тому, якщо ці оператори використовуються зі значеннями не булевого типу, вони повернуть значення не булевого типу. Логічні оператори описані у наведеній нижче таблиці.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Логічні оператори
ОператорЗастосуванняОпис
Логічне І (&&)expr1 && expr2Вертає вираз expr1, якщо він може бути перетворений на false; інакше, повертає expr2. Таким чином, при використанні з булевими значеннями && вертає true, якщо обидва операнди дорівнюють true; інакше, вертає false.
Логічне АБО (||)expr1 || expr2Вертає вираз expr1, якщо він може бути перетворений на true; інакше, вертає expr2. Таким чином, при використанні з булевими значеннями || вертає true, якщо будь-який з операндів дорівнює true; якщо обидва дорівнюють false, вертає false.
Логічне НЕ (!)!exprВертає false, якщо його єдиний операнд може бути перетворений на true; інакше, вертає true.
+ +

Прикладами виразів, які можуть бути перетворені на false, є ті, які повертають null, 0, NaN, порожній рядок ("") або undefined.

+ +

Наступний код демонструє приклади оператора && (логічне І).

+ +
var a1 =  true && true;     // t && t вертає true
+var a2 =  true && false;    // t && f вертає false
+var a3 = false && true;     // f && t вертає false
+var a4 = false && (3 == 4); // f && f вертає false
+var a5 = 'Кіт' && 'Пес';    // t && t вертає Пес
+var a6 = false && 'Кіт';    // f && t вертає false
+var a7 = 'Кіт' && false;    // t && f вертає false
+
+ +

Наступний код демонструє приклади оператора || (логічне АБО).

+ +
var o1 =  true || true;     // t || t вертає true
+var o2 = false || true;     // f || t вертає true
+var o3 =  true || false;    // t || f вертає true
+var o4 = false || (3 == 4); // f || f вертає false
+var o5 = 'Кіт' || 'Пес';    // t || t вертає Кіт
+var o6 = false || 'Кіт';    // f || t вертає Кіт
+var o7 = 'Кіт' || false;    // t || f вертає Кіт
+
+ +

Наступний код демонструє приклади оператора ! (логічне НЕ).

+ +
var n1 = !true;  // !t вертає false
+var n2 = !false; // !f вертає true
+var n3 = !'Кіт'; // !t вертає false
+
+ +

Коротке замикання обчислення

+ +

Оскільки логічні вирази обчислюються зліва направо, вони перевіряються на можливе "коротке замикання" обчислення за наступними правилами:

+ + + +

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

+ +

Рядкові оператори

+ +

На додачу до операторів порівняння, які можуть застосовуватись до рядкових значень, оператор конкатенації (+) об'єднує значення двох рядків, повертаючи інший рядок, який є об'єднанням рядків двох операндів.

+ +

Наприклад,

+ +
console.log('мій ' + 'рядок'); // консоль виводить рядок "мій рядок".
+ +

Скорочений оператор присвоєння += також може застосовуватись для конкатенації рядків.

+ +

Наприклад,

+ +
var mystring = 'алфа';
+mystring += 'віт'; // повертає "алфавіт" та присвоює це значення mystring.
+ +

Умовний (тернарний) оператор

+ +

Умовний оператор - єдиний оператор у JavaScript, який приймає три операнди. У оператора може бути одне чи два значення, в залежності від умови. Використовує наступний синтакс:

+ +
умова ? значення1 : значення2
+
+ +

Якщо умова дорівнює true, оператор повертає значення1.  В іншому випадку - значення2. Умовний оператор можна використовувати будь-де, де використовується звичайний оператор. Наприклад:

+ +
var status = (age >= 18) ? 'дорослий' : 'неповнолітній';
+
+ +

Ця інструкція присвоює значення "дорослий" змінній status, якщо значення age (вік) більше чи дорівнює 18. Інакше, вона присвоює змінній status значення "неповнолітній".

+ +

Оператор кома

+ +

Оператор кома (,) просто обчислює обидва свої операнди та повертає значення останнього операнда. Цей оператор найчастіше використовується всередині циклу for, що дозволяє оновлювати більше однієї змінної на кожному проході циклу.

+ +

Наприклад, якщо a є двовимірним масивом з 10 елементами по кожній стороні, наступний код використовує оператор кома, щоб оновити дві змінні одночасно. Код виводить значення діагональних елементів масиву:

+ +
for (var i = 0, j = 9; i <= j; i++, j--)
+  console.log('a[' + i + '][' + j + ']= ' + a[i][j]);
+
+ +

Унарні оператори

+ +

Унарна операція - це операція лише з одним операндом.

+ +

delete

+ +

Оператор delete видаляє об'єкт, властивість об'єкта або елемент за вказаним індексом у масиві. Синтаксис наступний:

+ +
delete objectName;
+delete objectName.property;
+delete objectName[index];
+delete property; // працює лише всередині конструкції with
+
+ +

де objectName є іменем об'єкта, property - існуюча властивість, а index - ціле число, що вказує розташування елемента у масиві.

+ +

Четверта форма працює лише всередині блоку with для видалення властивості об'єкта.

+ +

Ви можете використовувати оператор delete для видалення змінних, оголошених неявно, але не тих, що були оголошені оператором var.

+ +

Якщо оператор delete відпрацьовує успішно, значенням властивості чи елемента стає undefined. Оператор delete повертає true, якщо операція можлива; він повертає false, якщо операція неможлива.

+ +
x = 42;
+var y = 43;
+myobj = new Number();
+myobj.h = 4;    // створює властивість h
+delete x;       // вертає true (можна видалити властивість, оголошену неявно)
+delete y;       // вертає false (не можна видалити властивість, оголошену через var)
+delete Math.PI; // вертає false (не можна видаляти попередньо визначені властивості)
+delete myobj.h; // вертає true (можна видалити властивість, визначену користувачем)
+delete myobj;   // вертає true (можна видалити, якщо властивість оголошена неявно)
+
+ +
Видалення елементів масиву
+ +

Коли ви видаляєте елемент масиву, це не впливає на довжину масиву. Для прикладу, якщо ви видалите a[3], a[4] досі є a[4], а a[3] дорівнює undefined.

+ +

Коли оператор delete видаляє елемент масиву, цей елемент більше не існує у масиві. У наступному прикладі trees[3] видаляється оператором delete. Однак, адреса trees[3] досі доступна та повертає undefined.

+ +
var trees = ['секвоя', 'лавр', 'кедр', 'дуб', 'клен'];
+delete trees[3];
+if (3 in trees) {
+  // це не виконається
+}
+
+ +

Якщо вам потрібно, щоб елемент існував, але мав значення undefined, скористайтесь ключовим словом undefined замість оператора delete. У наступному прикладі trees[3] присвоюється значення undefined, але елемент масиву досі існує:

+ +
var trees = ['секвоя', 'лавр', 'кедр', 'дуб', 'клен'];
+trees[3] = undefined;
+if (3 in trees) {
+  // це виконається
+}
+
+ +

typeof

+ +

Оператор typeof використовується наступним чином:

+ +
typeof операнд
+typeof (операнд)
+
+ +

Оператор typeof повертає рядок, що вказує тип необчисленого операнда. Операнд є рядком, змінною, ключовим словом чи об'єктом, для якого треба повернути тип. Круглі дужки є необов'язковими.

+ +

Припустимо, ви визначили наступні змінні:

+ +
var myFun = new Function('5 + 2');
+var shape = 'коло';
+var size = 1;
+var foo = ['Яблуко', 'Манго', 'Апельсин'];
+var today = new Date();
+
+ +

Оператор typeof вертає наступні результати для цих змінних:

+ +
typeof myFun;       // вертає "function"
+typeof shape;       // вертає "string"
+typeof size;        // вертає "number"
+typeof foo;         // вертає "object"
+typeof today;       // вертає "object"
+typeof doesntExist; // вертає "undefined"
+
+ +

Для ключових слів true та null оператор typeof вертає наступні результати:

+ +
typeof true; // вертає "boolean"
+typeof null; // вертає "object"
+
+ +

Для числа та рядка оператор typeof вертає наступні результати:

+ +
typeof 62;            // вертає "number"
+typeof 'Hello world'; // вертає "string"
+
+ +

Для значень властивостей оператор typeof вертає тип значення, яке містить ця властивість:

+ +
typeof document.lastModified; // вертає "string"
+typeof window.length;         // вертає "number"
+typeof Math.LN2;              // вертає "number"
+
+ +

Для методів та функцій оператор typeof вертає наступні результати:

+ +
typeof blur;        // вертає "function"
+typeof eval;        // вертає "function"
+typeof parseInt;    // вертає "function"
+typeof shape.split; // вертає "function"
+
+ +

Для попередньо визначених об'єктів оператор typeof вертає наступні результати:

+ +
typeof Date;     // вертає "function"
+typeof Function; // вертає "function"
+typeof Math;     // вертає "object"
+typeof Option;   // вертає "function"
+typeof String;   // вертає "function"
+
+ +

void

+ +

Оператор void використовується наступним чином:

+ +
void (вираз)
+void вираз
+
+ +

Оператор void вказує, що вираз має бути обчислений без повернення значення. Вираз є виразом JavaScript, який треба обчислити. Дужки, що оточують вираз, є необов'язковими, але вживати їх є гарним стилем.

+ +

Ви можете скористатись оператором void, щоб вказати вираз як гіпертекстове посилання. Вираз обчислюється, але не завантажується на місці відкритого документа.

+ +

Наступний код створює гіпертекстове посилання, яке нічого не робить, коли користувач на нього натискає. Коли користувач натискає на посилання, void(0) обчислюється як undefined, що не має жодного ефекту у JavaScript.

+ +
<a href="javascript:void(0)">Натисніть сюди, щоб нічого не робити</a>
+
+ +

Наступний код створює гіпертекстове посилання, яке відправляє форму, коли користувач натискає на нього.

+ +
<a href="javascript:void(document.form.submit())">
+Натисніть сюди, щоб відправити</a>
+ +

Оператори відношення

+ +

Оператор відношення порівнює свої операнди та повертає значення Boolean, на підставі того, чи є порівняння істиною.

+ +

in

+ +

Оператор in повертає true, якщо вказана властивість існує на вказаному об'єкті. Синтаксис наступний:

+ +
propNameOrNumber in objectName
+
+ +

де propNameOrNumber є рядковим або числовим виразом, який відображає ім'я властивості або індекс у масиві, а objectName є ім'ям об'єкта.

+ +

Наступний приклад демонструє варіанти використання оператора in.

+ +
// Масиви
+var trees = ['секвоя', 'лавр', 'кедр', 'дуб', 'клен'];
+0 in trees;        // вертає true
+3 in trees;        // вертає true
+6 in trees;        // вертає false
+'лавр' in trees;    // вертає false (ви маєте вказати індекс,
+                   // а не значення за цим індексом)
+'length' in trees; // вертає true (length є властивістю масиву)
+
+// вбудовані об'єкти
+'PI' in Math;          // вертає true
+var myString = new String('корал');
+'length' in myString;  // вертає true
+
+// Користувацькі об'єкти
+var mycar = { make: 'Honda', model: 'Accord', year: 1998 };
+'make' in mycar;  // вертає true
+'model' in mycar; // вертає true
+
+ +

instanceof

+ +

Оператор instanceof повертає true, якщо вказаний об'єкт належить до вказаного типу. Синтаксис наступний:

+ +
objectName instanceof objectType
+
+ +

де objectName є ім'ям об'єкта, який порівнюється з objectType, а objectType є типом об'єкта, наприклад, {{jsxref("Date")}} або {{jsxref("Array")}}.

+ +

Використовуйте instanceof, коли вам необхідно підтвердити тип об'єкта під час виконання. Наприклад, перехоплюючи винятки, ви можете зробити відгалуження до іншого коду обробки винятків, в залежності від типу викинутого винятку.

+ +

Наприклад, наступний код використовує instanceof для визначення того, чи theDay є об'єктом Date. Оскільки theDay є об'єктом Date, інструкції у блоці if будуть виконані.

+ +
var theDay = new Date(1995, 12, 17);
+if (theDay instanceof Date) {
+  // інструкції для виконання
+}
+
+ +

Пріоритет операторів

+ +

Пріоритет операторів визначає порядок, у якому вони застосовуються під час обчислення виразу. Ви можете змінити пріоритет оператора, використавши дужки.

+ +

Наступна таблиця наводить пріоритети операторів, від найвищого до найнижчого.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Пріоритет операторів
Тип оператораОкремі оператори
властивість. []
виклик / створення екземпляра() new
заперечення / інкремент! ~ - + ++ -- typeof void delete
множення / ділення* / %
додавання / віднімання+ -
бітовий зсув<< >> >>>
відношення< <= > >= in instanceof
рівність== != === !==
побітове-і&
виключне-побітове-або^
побітове-або|
логічне-і&&
логічне-або||
умовний?:
присвоєння= += -= *= /= %= <<= >>= >>>= &= ^= |=
кома,
+ +

Більш детальну версію цієї таблиці, доповнену посиланнями на додаткові подробиці щодо кожного оператора, можна знайти у довіднику з JavaScript.

+ +

Вирази

+ +

Виразом є будь-яка одиниця коду, яка вирішується з певним значенням.

+ +

Кожний синтаксично коректний вираз вирішується з якимось значенням, але, концептуально, існують два типи виразів: з побічними ефектами (наприклад: ті, що присвоюють значення змінній) та такі, що обчислюються і, таким чином, вирішуються з певним значенням.

+ +

Вираз x = 7 є прикладом першого типу. Цей вираз використовує оператор = для присвоєння семи змінній x. Сам вираз обчислюється з результатом сім.

+ +

Код 3 + 4 є прикладом другого типу виразів. Цей вираз за допомогою оператора + складає три та чотири без присвоєння результату, семи, змінній.
+
+ JavaScript має наступні категорії виразів:

+ + + +

Первинні вирази

+ +

Базові ключові слова та загальні вирази у JavaScript.

+ +

this

+ +

Використовуйте ключове слово this для посилання на поточний об'єкт. Загалом, this у методі посилається на об'єкт, що його викликав. Використовуйте this або з крапкою, або з дужковою нотацією:

+ +
this['propertyName']
+this.propertyName
+
+ +

Припустимо, функція на ім'я validate перевіряє властивість об'єкта value, маючи найменше та найбільше значення:

+ +
function validate(obj, lowval, hival) {
+  if ((obj.value < lowval) || (obj.value > hival))
+    console.log('Некоректне значення!');
+}
+
+ +

Ви можете викликати validate в кожному обробнику подій елементів форми onChange, використовуючи this, щоб передати йому елемент форми, як у наступному прикладі:

+ +
<p>Введіть число між 18 та 99:</p>
+<input type="текст" name="вік" size=3 onChange="validate(this, 18, 99);">
+
+ +

Оператор групування

+ +

Оператор групування ( ) контролює пріоритет обчислення у виразах. Наприклад, ви можете змінити обчислення спочатку множення та ділення, а потім додавання та віднімання, щоб обчислити спочатку додавання.

+ +
var a = 1;
+var b = 2;
+var c = 3;
+
+// пріоритет за замовчуванням
+a + b * c     // 7
+// обчислюється наступним чином
+a + (b * c)   // 7
+
+// тепер змінюємо пріоритет
+// додавання перед множенням
+(a + b) * c   // 9
+
+// що є рівнозначним
+a * c + b * c // 9
+
+ +

Лівосторонні вирази

+ +

Значення зліва є призначенням присвоєння.

+ +

new

+ +

Ви можете скористатись оператором new, щоб створити екземпляр визначеного користувачем типу об'єкта або одного з вбудованих типів. Використовуйте new наступним чином:

+ +
var objectName = new objectType([param1, param2, ..., paramN]);
+
+ +

super

+ +

Ключове слово super використовується для виклику функцій батьківського об'єкта. Воно корисне для використання з класами, для виклику батьківського конструктора, наприклад.

+ +
super([arguments]); // викликає батьківський конструктор.
+super.functionOnParent([arguments]);
+
+ +

Оператор розпакування

+ +

Оператор розпакування дозволяє розкласти вираз там, де очікується більше одного аргументу (для викликів функцій) або більше одного елемента (для масивних літералів).

+ +

Приклад: Сьогодні, якщо ви маєте масив та бажаєте створити новий масив, використавши існуючий масив як його частину, синтаксису масивного літералу більше недостатньо, і вам доводиться повертатись до імперативного коду, використовуючи комбінацію з push, splice, concat, і т. д. З оператором розпакування все стає набагато лаконічнішим:

+ +
var parts = ['плечі', 'коліна'];
+var lyrics = ['голова', ...parts, 'та', 'пальці'];
+ +

Схожим чином оператор розпакування працює з викликами функцій:

+ +
function f(x, y, z) { }
+var args = [0, 1, 2];
+f(...args);
+ +
{{PreviousNext("Web/JavaScript/Guide/Functions", "Web/JavaScript/Guide/Numbers_and_dates")}}
-- cgit v1.2.3-54-g00ecf