--- language: javascript contributors: - ["Adam Brenecki", "http://adam.brenecki.id.au"] - ["Ariel Krakowski", "http://www.learneroo.com"] filename: javascript-ru.js translators: - ["Alexey Gonchar", "http://github.com/finico"] lang: ru-ru --- JavaScript был создан в 1995 году Бренданом Айком, работающим в компании Netscape. Изначально он был задуман как простой язык сценариев для веб-сайтов, дополняющий Java для более сложных веб-приложений, но его тесная интеграция с веб-страницами и втроенная поддержка браузерами привели к тому, что он стал более распространённым, чем 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 // Побитовые операции также имеются; они производят операции, используя // двоичное представление числа, и возвращают новую последовательность из // 32 бит (число) в качестве результата. 1 << 2; // = 4 // Приоритет в выражениях явно задаётся скобками. (1 + 3) * 2; // = 8 // Есть три специальных значения, которые не являются реальными числами: Infinity; // "бесконечность", например, результат деления на 0 -Infinity; // "минус бесконечность", результат деления отрицательного числа на 0 NaN; // "не число", например, результат деления 0/0 // Существует также логический тип. true; false; // Строки создаются при помощи двойных или одинарных кавычек. 'abc'; "Hello, world"; // Для логического отрицания используется символ восклицательного знака. !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 "This is a string".charAt(0); // = 'T' // ...или используйте метод 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 *= 10; // теперь someVar имеет значение 100 // а так же специальные операторы инкремент и декремент для увеличения и // уменьшения переменной на единицу соответственно someVar++; // теперь someVar имеет значение 101 someVar--; // обратно 100 // Массивы это нумерованные списки из значений любого типа. var myArray = ["Hello", 45, true]; // Их элементы могут быть доступны при помощи синтаксиса с квадратными скобками. // Индексы массивов начинаются с нуля. myArray[1]; // = 45 // Массивы можно изменять, как и их длину. myArray.push("World"); myArray.length; // = 4 // Добавлять и редактировать определенный элемент myArray[3] = "Hello"; // Объекты в 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) { // выполняется, если count равен 4 } else { // выполняется, если не 3 и не 4 } // Как это делает 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.colour == "blue") { house.contains = "bear"; } if (colour == "red" || colour == "blue") { // цвет красный или синий } // || используется как "короткий цикл вычисления" для присваивания переменных. var name = otherName || "default"; // Оператор switch выполняет проверку на равенство пр помощи === // используйте break чтобы прервать выполнение после каждого case // или выполнение пойдёт далее, игнорируя при этом остальные проверки. grade = 'B'; switch (grade) { case 'A': console.log("Great job"); break; case 'B': console.log("OK job"); break; case 'C': console.log("You can do better"); break; default: console.log("Oy vey"); break; } /////////////////////////////////// // 4. Функции, Область видимости и Замыкания // Функции в JavaScript объявляются при помощи ключевого слова function. function myFunction(thing) { return thing.toUpperCase(); } myFunction("foo"); // = "FOO" // Обратите внимание, что значение, которое будет возвращено, должно начинаться // на той же строке, что и ключевое слово return, в противном случае вы будете // всегда возвращать undefined по причине автоматической вставки точки с запятой. // Следите за этим при использовании стиля форматирования Allman. function myFunction() { return // <- здесь точка с запятой вставится автоматически { thisIsAn: 'object literal' } } myFunction(); // = undefined // JavaScript функции - это объекты, поэтому они могут быть переприсвоены на // различные имена переменных и передаваться другим функциям в качестве аргументов, // например, когда назначается обработчик события: function myFunction() { // этот код будет вызван через 5 секунд } setTimeout(myFunction, 5000); // Примечание: setTimeout не является частью языка, но реализован в браузерах и Node.js // Функции не обязательно должны иметь имя при объявлении - вы можете написать // анонимное определение функции непосредственно в агрументе другой функции. setTimeout(function() { // этот код будет вызван через 5 секунд }, 5000); // В JavaScript есть область видимости функции; функции имеют свою область // видимости, а другие блоки - нет. if (true) { var i = 5; } i; // = 5 - не undefined как ожидалось бы в языках с блочной областью видимости // Это привело к общепринятому шаблону "самозапускающихся анонимных функций", // которые препятствуют проникновению переменных в глобальную область видимости (function() { var temporary = 5; // Мы можем получить доступ к глобальной области для записи в "глобальный объект", // который в веб-браузере всегда window. Глобальный объект может иметь другое // имя в таких платформах, как Node.js window.permanent = 10; })(); temporary; // вызовет сообщение об ошибке с типом ReferenceError permanent; // = 10 // Одной из самых мощных возможностей JavaScript являются замыкания. Если функция // определена внутри другой функции, то внутренняя функция имеет доступ к // переменным внешней функции, даже после того, как контекст выполнения выйдет из // внешней функции. function sayHelloInFiveSeconds(name) { var prompt = "Hello, " + name + "!"; // Внутренние функции по умолчанию помещаются в локальную область видимости, // как если бы они были объявлены с var. function inner() { alert(prompt); } setTimeout(inner, 5000); // setTimeout асинхронна, поэтому функция sayHelloInFiveSeconds сразу выйдет // и тело setTimeout будет вызвано позже. Однако, поскольку внутренняя // функция "замкнута", она по-прежнему имеет доступ к переменной prompt, // когда sayHelloInFiveSeconds вызывется. } sayHelloInFiveSeconds("Adam"); // откроется окно с "Hello, Adam!" через 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!" // Какое это значение имеет к тому, как вызвана функция и где она определена. // Итак, наша функция не работает, если она вызывается не в контексте объекта. var myFunc = myObj.myFunc; myFunc(); // = undefined // И наоборот, функция может быть присвоена объекту и получать доступ к нему // через this, даже если она не была присвоена при объявлении. var myOtherFunc = function() { } myObj.myOtherFunc = myOtherFunc; myObj.myOtherFunc(); // = "HELLO WORLD!" // Мы можем также указать контекст для выполнения функции, когда мы вызываем ее // с помощью call или apply. var anotherFunc = function(s) { return this.myString + s; } anotherFunc.call(myObj, " And Hello Moon!"); // = "Hello World! And Hello Moon!" // Функция apply аналогична, но принимает массив аргументов. anotherFunc.apply(myObj, [" And Hello Sun!"]); // = "Hello World! And Hello Sun!" // Это полезно при работе с функцией, которая принимает последовательность // аргументов, и вы хотите передать массив. 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(" And Hello Saturn!"); // = "Hello World! And Hello Saturn!" // 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 // Каждый объект в JavaScript имеет свойтво prototype. Когда вы хотите получить // доступ к свойтву объекта, которое не существует в этом объекте, интерпретатор // будет искать это свойство в прототипе. // Некоторые реализации языка позволяют получить доступ к объекту прототипа // через свойство __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, который появился в ECMAScript 5 и есть еще // не во всех реализациях языка. 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 - это ложь. } if (Number(0)) { // Этот код выполнится, потому что Number(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(); } } ``` ## Что еще почитать [Современный учебник JavaScript (Илья Кантор)](http://learn.javascript.ru) - качественный учебник по JavaScript на русском языке. [Mozilla Developer Network](https://developer.mozilla.org/ru/docs/Web/JavaScript) - предоставляет отличную документацию для JavaScript, как он используется в браузерах. Кроме того, это вики, поэтому, если вы знаете больше, вы можете помочь другим, делясь своими знаниями. [JavaScript Garden](http://bonsaiden.github.io/JavaScript-Garden/ru/) - это подробное руководство всех неинтуитивных особенностей языка. [Stack Overflow](http://stackoverflow.com/questions/tagged/javascript) - можно найти ответ почти на любой ваш вопрос, а если его нет, то задать вопрос самому.