--- language: javascript contributors: - ["Adam Brenecki", "http://adam.brenecki.id.au"] - ["Ariel Krakowski", "http://www.learneroo.com"] filename: javascript-ua.js translators: - ["Ivan Neznayu", "https://github.com/IvanEh"] - ["Serhii Maksymchuk", "https://maximchuk.tk"] lang: uk-ua --- JavaScript було створено в 1995 році Бренданом Айком, який працював у копаніх Netscape. Він був задуманий як проста мова сценаріїв для веб-сайтів, який би доповнював Java для більш складних веб-застосунків. Але тісна інтеграція з веб-сторінками і вбудована підтримка браузерами призвела до того, що JavaScript став популярніший за власне Java. Зараз JavaScript не обмежується тільки веб-браузеорм. Наприклад, Node.js, програмна платформа, що дозволяє виконувати JavaScript код з використанням рушія V8 від браузера Google Chrome, стає все більш і більш популярною. ```js // С-подібні коментарі. Однорядкові коментарі починаються з двох символів /(слеш) /* а багаторядкові коментарі починаються з послідовності слеша та зірочки і закінчуються символами зірочка-слеш */ //Інструкції можуть закінчуватися крапкою з комою ; doStuff(); // ... але не обов’язково, тому що крапка з комою автоматично вставляється на // місці символу нового рядка, крім деяких випадків. doStuff() // Ми завжди будемо використовувати крапку з комою в цьому посібнику, тому що ці // винятки можуть призвести до неочікуваних результатів /////////////////////////////////// // 1. Числа, Рядки і Оператори // В JavaScript числа зберігаються тільки в одному форматі (64-bit IEEE 754 double) // Цей тип має 52-бітну мантису, якої достатньо для збереження чисел з // точністю до 9✕10¹⁵. 3; // = 3 1.5; // = 1.5 // Деякі прості арифметичні операції працють так, як ми очікуємо. 1 + 1; // = 2 0.1 + 0.2; // = 0.30000000000000004 (а деякі - ні) 8 - 1; // = 7 10 * 2; // = 20 35 / 5; // = 7 // В тому числі ділення з остачею 5 / 2; // = 2.5 // В JavaScript є побітові операції; коли ви виконуєте таку операцію, // число з плаваючою точкою переводиться в ціле зі знаком // довжиною *до* 32 розрядів. 1 << 2; // = 4 // Пріоритет у виразах можна задати явно круглими дужками (1 + 3) * 2; // = 8 // Є три спеціальні значення, які не є реальними числами: Infinity; // "нескінченність", наприклад, як результат ділення на 0 -Infinity; // "мінус нескінченність", як результат ділення від’ємного числа на 0 NaN; // "не число", наприклад, ділення 0/0 // Логічні типи true; false; // Рядки створюються за допомогою подвійних та одинарних лапок 'абв'; "Світ, привіт!"; // Для логічного заперечення використовується знак оклику. !true; // = false !false; // = true // Строга рівність === 1 === 1; // = true 2 === 1; // = false // Строга нерівність !== 1 !== 1; // = false 2 !== 1; // = true // Інші оператори порівняння 1 < 10; // = true 1 > 10; // = false 2 <= 2; // = true 2 >= 2; // = true // Рядки об’єднуються за допомогою оператора + "hello, " + "world!"; // = "hello, world!" // І порівнюються за допомогою > та < "a" < "b"; // = true // Перевірка на рівність з приведнням типів здійснюється оператором == "5" == 5; // = true null == undefined; // = true // ... але приведення не виконується при === "5" === 5; // = false null === undefined; // = false // ... приведення типів може призвести до дивних результатів 13 + !0; // 14 "13" + !0; // '13true' // Можна отримати доступ до будь-якого символа рядка за допомгою charAt "Це рядок".charAt(0); // = 'Ц' // ... або використати метод substring, щоб отримати більший кусок "Hello, world".substring(0, 5); // = "Hello" // length - це не метод, а поле "Hello".length; // = 5 // Типи null и undefined null; // навмисна відсутність результату undefined; // використовується для позначення відсутності присвоєного значення // false, null, undefined, NaN, 0 та "" — хиба; все інше - істина. // Потрібно відмітити, що 0 — це хиба, а "0" — істина, не зважаючи на те що: // 0 == "0". /////////////////////////////////// // 2. Змінні, Масиви, Об’єкти // Змінні оголошуються за допомогою ключового слова var. JavaScript — мова з // динамічною типізацією, тому не потрібно явно вказувати тип. Для присвоєння // значення змінної використовується символ = var someVar = 5; // якщо пропустити слово var, ви не отримаєте повідомлення про помилку, ... someOtherVar = 10; // ... але ваша змінна буде створена в глобальному контексті, а не там, де // ви її оголосили // Змінні, які оголошені без присвоєння, автоматично приймають значення undefined var someThirdVar; // = undefined // У математичних операцій є скорочені форми: someVar += 5; // як someVar = someVar + 5; someVar *= 10; // тепер someVar = 100 // Інкремент і декремент someVar++; // тепер someVar дорівнює 101 someVar--; // а зараз 100 // Масиви — це нумеровані списки, які зберігають значення будь-якого типу. var myArray = ["Привіт", 45, true]; // Доступ до елементів можна отримати за допомогою синтаксиса з квадратними дужками // Індексація починається з нуля myArray[1]; // = 45 // Масиви можна змінювати, як і їх довжину myArray.push("Привіт"); myArray.length; // = 4 // Додавання і редагування елементів myArray[3] = "світ"; // Об’єкти в JavaScript схожі на словники або асоціативні масиви в інших мовах var myObj = {key1: "Hello", key2: "World"}; // Ключі - це рядки, але лапки не обов’язкі, якщо ключ задовольняє // правилам формування назв змінних. Значення можуть бути будь-яких типів. var myObj = {myKey: "myValue", "my other key": 4}; // Атрибути можна отримати використовуючи квадратні дужки myObj["my other key"]; // = 4 // Або через точку, якщо ключ є правильним ідентифікатором myObj.myKey; // = "myValue" // Об’єкти можна динамічно змінювати й додавати нові поля myObj.myThirdKey = true; // Коли ви звертаєтесь до поля, що не існує, ви отримуєте значення undefined myObj.myFourthKey; // = undefined /////////////////////////////////// // 3. Керуючі конструкції // Синтаксис для цього розділу майже такий самий, як у Java // Умовна конструкція var count = 1; if (count == 3) { // виконується, якщо count дорівнює 3 } else if (count == 4) { // .. } else { // ... } // ... цикл while. while (true){ // Нескінченний цикл! } // Цикл do-while такий самий, як while, але завжди виконується принаймні один раз. var input do { input = getInput(); } while (!isValid(input)) // цикл for такий самий, як в C і Java: // ініціалізація; умова; крок. for (var i = 0; i < 5; i++) { // виконається 5 разів } // && — логічне І, || — логічне АБО if (house.size == "big" && house.color == "blue") { house.contains = "bear"; } if (color == "red" || color == "blue") { // колір червоний або синій } // && та || використовують скорочене обчислення // тому їх можна використовувати для задання значень за замовчуванням. var name = otherName || "default"; // Оператор switch виконує перевірку на рівність за допомогою === // використовуйте break, щоб призупити виконання наступного case, grade = 4; switch (grade) { case 5: console.log("Відмінно"); break; case 4: console.log("Добре"); break; case 3: console.log("Можна краще"); break; default: console.log("Погано!"); break; } /////////////////////////////////// // 4. Функції, область видимості і замикання // Функції в JavaScript оголошуються за допомогою ключового слова function. function myFunction(thing) { return thing.toUpperCase(); } myFunction("foo"); // = "FOO" // Зверність увагу, що значення яке буде повернено, повинно починатися на тому ж // рядку, що і ключове слово return, інакше завжди буде повертатися значення undefined // через автоматичну вставку крапки з комою function myFunction() { return // <- крапка з комою вставляється автоматично { thisIsAn: 'object literal' } } myFunction(); // = undefined // В JavaScript функції - це об`єкти першого класу, тому вони можуть присвоюватися // іншим змінним і передаватися іншим функціям, наприклад, щоб визначити обробник // події. function myFunction() { // код буде виконано через 5 сек. } setTimeout(myFunction, 5000); // setTimeout не є частиною мови, але реалізований в браузерах і Node.js // Функції не обов’язково мають мати ім’я при оголошенні — ви можете написати // анонімну функцію прямо в якості аргумента іншої функції setTimeout(function() { // Цей код буде виконано через п’ять секунд }, 5000); // В JavaScript реалізована концепція області видимості; функції мають свою // область видимості, а інші блоки не мають if (true) { var i = 5; } i; // = 5, а не undefined, як це звичайно буває в інших мовах // Така особливість призвела до шаблону "анонімних функцій, які викликають самих себе" // що дозволяє уникнути проникнення змінних в глобальну область видимості (function() { var temporary = 5; // об’єкт window зберігає глобальний контекст; таким чином ми можемо також додавати // змінні до глобальної області window.permanent = 10; })(); temporary; // повідомлення про помилку ReferenceError permanent; // = 10 // Замикання - один з найпотужніших інтрументів JavaScript. Якщо функція визначена // всередині іншої функції, то внутрішня функція має доступ до змінних зовнішньої // функції навіть після того, як код буде виконуватися поза контекстом зовнішньої функції function sayHelloInFiveSeconds(name) { var prompt = "Привіт, " + name + "!"; // Внутрішня функція зберігається в локальній області так, // ніби функція була оголошена за допомогою ключового слова var function inner() { alert(prompt); } setTimeout(inner, 5000); // setTimeout асинхронна, тому функція sayHelloInFiveSeconds одразу завершиться, // після чого setTimeout викличе функцію inner. Але функція inner // «замкнута» кругом sayHelloInFiveSeconds, вона все рівно має доступ до змінної prompt } sayHelloInFiveSeconds("Адам"); // Через 5 с відкриється вікно «Привіт, Адам!» /////////////////////////////////// // 5. Об’єкти: конструктори і прототипи // Об’єкти можуть містити функції var myObj = { myFunc: function() { return "Hello, world!"; } }; myObj.myFunc(); // = "Hello, world!" // Функції, що прикріплені до об’єктів мають доступ до поточного об’єкта за // допомогою ключового слова this. myObj = { myString: "Hello, world!", myFunc: function() { return this.myString; } }; myObj.myFunc(); // = "Hello, world!" // Значення this залежить від того, як функція викликається // а не від того, де вона визначена. Таким чином наша функція не працює, якщо // вона викликана не в контексті об’єкта var myFunc = myObj.myFunc; myFunc(); // = undefined // Функція може бути присвоєна іншому об’єкту. Тоді вона матиме доступ до // цього об’єкта через this var myOtherFunc = function() { } myObj.myOtherFunc = myOtherFunc; myObj.myOtherFunc(); // = "HELLO, WORLD!" // Контекст виконання функції можна задати за допомогою сall або apply var anotherFunc = function(s) { return this.myString + s; } anotherFunc.call(myObj, " Hello!"); // = "Hello, world! Hello!" // Функцiя apply приймає в якості аргументу масив anotherFunc.apply(myObj, [" Hello!"]); // = "Hello, world! Hello!" // apply можна використати, коли функція працює послідовністю аргументів, а // ви хочете передати масив Math.min(42, 6, 27); // = 6 Math.min([42, 6, 27]); // = NaN (Ой-ой!) Math.min.apply(Math, [42, 6, 27]); // = 6 // Але call і apply — тимчасові. Коли ми хочемо зв’язати функцію і об’єкт // використовують bind var boundFunc = anotherFunc.bind(myObj); boundFunc(" Hello!"); // = "Hello world, Hello!" // Bind можна використати для задання аргументів var product = function(a, b) { return a * b; } var doubler = product.bind(this, 2); doubler(8); // = 16 // Коли ви викликаєте функцію за допомогою ключового слова new, створюється новий об’єкт, // доступний функції за допомогою this. Такі функції називають конструкторами. var MyConstructor = function() { this.myNumber = 5; } myNewObj = new MyConstructor(); // = {myNumber: 5} myNewObj.myNumber; // = 5 // У кожного об’єкта є прототип. Коли ви звертаєтесь до поля, яке не існує в цьому // об’єкті, інтерпретатор буде шукати поле в прототипі // Деякі реалізації мови дозволяють отримати доступ до прототипа об’єкта через // "магічну" властивість __proto__. Це поле не є частиною стандарта, але існують // стандартні способи використання прототипів, які ми побачимо пізніше var myObj = { myString: "Hello, world!" }; var myPrototype = { meaningOfLife: 42, myFunc: function() { return this.myString.toLowerCase() } }; myObj.__proto__ = myPrototype; myObj.meaningOfLife; // = 42 // Аналогічно для функцій myObj.myFunc(); // = "Hello, world!" // Якщо інтерпретатор не знайде властивість в прототипі, то він продовжить пошук // в прототипі прототипа і так далі myPrototype.__proto__ = { myBoolean: true }; myObj.myBoolean; // = true // Кожен об’єкт зберігає посилання на свій прототип. Це значить, що ми можемо змінити // наш прототип, і наші зміни будуть всюди відображені. myPrototype.meaningOfLife = 43; myObj.meaningOfLife; // = 43 // Ми сказали, що властивість __proto__ нестандартна, і нема ніякого стандартного способу // змінити прототип об’єкта, що вже існує. Але є два способи створити новий об’єкт із заданим // прототипом // Перший спосіб — це Object.create, який з’явився в JavaScript недавно, // а тому в деяких реалізаціях може бути недоступним. var myObj = Object.create(myPrototype); myObj.meaningOfLife; // = 43 // Другий спосіб: у конструкторів є властивість з іменем prototype. Це *не* // прототип функції-конструктора, це прототип для нових об’єктів, які будуть створені // цим конструктором і ключового слова new. MyConstructor.prototype = { myNumber: 5, getMyNumber: function() { return this.myNumber; } }; var myNewObj2 = new MyConstructor(); myNewObj2.getMyNumber(); // = 5 myNewObj2.myNumber = 6 myNewObj2.getMyNumber(); // = 6 // У вбудованих типів(рядок, число) теж є конструктори, які створють еквівалентні // об’єкти-обгортки var myNumber = 12; var myNumberObj = new Number(12); myNumber == myNumberObj; // = true // Але вони не ідентичні typeof myNumber; // = 'number' typeof myNumberObj; // = 'object' myNumber === myNumberObj; // = false if (0) { // Цей код не виконається, тому що 0 - це хиба. } // Об’єкти-обгортки і вбудовані типи мають спільні прототипи, тому // ви можете розширити функціонал рядків: String.prototype.firstCharacter = function() { return this.charAt(0); } "abc".firstCharacter(); // = "a" // Такий прийом часто використовуються в поліфілах, які реалізують нові можливості // JavaScript в старій реалізації мови, так що вони можуть бути використані в старих // середовищах // Наприклад, Object.create доступний не у всіх реалізаціях, але ми можемо // використати функції за допомогою наступного поліфіла: if (Object.create === undefined) { // не перезаписуємо метод, якщо він існує Object.create = function(proto) { // Створюємо правильний конструктор з правильним прототипом var Constructor = function(){}; Constructor.prototype = proto; return new Constructor(); } } ``` ## Що почитати [1]: https://developer.mozilla.org/en-US/docs/Web/JavaScript [2]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript [3]: https://developer.mozilla.org/en-US/docs/Using_the_W3C_DOM_Level_1_Core [4]: http://www.learneroo.com/modules/64/nodes/350 [5]: http://bonsaiden.github.io/JavaScript-Garden/ [6]: http://www.amazon.com/gp/product/0596805527/ [7]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript [8]: http://eloquentjavascript.net/ [9]: http://jstherightway.org/