Немного о JavaScript

В данный раздел я вынес ту информацию о JavaScript, которую необходимо знать, чтобы у вас не возникало «детских» проблем с использованием jQuery. Если у вас есть опыт работы с JavaScript, то листайте далее.

Изучать хотите JavaScript и jQuery? Так силу познайте инструмента истинного:

Список не полон, но console там есть, применять её надо уметь

О форматировании

Хотел бы сразу обратить внимание на форматирование JavaScript-кода. Мой опыт мне подсказывает — лучше всего спроецировать стандарты форматирования основного языка разработки на прикладной — JavaScript, а если вы хотите чего-нить из глобального и общепринятого, то я для вас уже погуглил:

В довесок поделюсь небольшим советом: все переменные, содержащие объект jQuery, лучше всего именовать, начиная с символа «$». Поверьте, такая небольшая хитрость экономит много времени. И ещё — в конце каждой строки я ставлю точку с запятой, сам JavaScript этого не требует, но и лишним не будет.

Основы JavaScript

Переменные

Первое, с чем мы столкнёмся – это объявление переменных:

var name = "Ivan";
var age = 32;

Всё просто, объявляем переменную, используя ключевое слово «var». Попробуйте и вы создать переменную x и присвойте ей значение 10:

Exercise
Correct!
False!

Можно, конечно же, и без «var», но делать я вам это настоятельно не рекомендую, т.к. могут возникнуть непредвиденные проблемы в коде, о чём чуть позже расскажу.

Да, да, JavaScript относится к языкам с динамической типизацией, и нам нет нужды указывать тип данных при объявлении переменных, вы даже можете устроить «holy war» по этому поводу, но делайте это локально, не выходя за рамки своей черепной коробки.

На имена переменных наложено два ограничения:

  • имя может состоять из букв, цифр, и символов «$» и «_»
  • первый символ не должен быть цифрой

Учтите, регистр букв имеет значение:

var company = "Facebook";
// совсем другая «компания»
var Company = "Google";

Хочу также вас познакомить с таким нововведением ECMAScript-2015 (в дальнейшем ES-2015), как объявление переменных с использованием конструкции «let»:

let company = "Facebook";

Внешне, от «var» не сильно отличается, зато какая разница в поведении:

  • область видимости переменной «let» ограничена блоком {...}, в отличие от «var», которая видна везде внутри функции:

    вот так ведёт себя переменная объявленная с помощью «var»:

    var a = 0;
    if (true) {
        var a = 1000;
        alert(a); // 1000
    }
    alert(a);     // 1000
    

    а теперь сравните с поведением «let»:

    let a = 0;
    if (true) {
        let a = 1000;
        alert(a); // 1000
    }
    alert(a);     // 0
    
  • переменная «let» видна только после объявления:

    «var»:

    alert(a);  // undefined
    var a = 0;
    

    «let»:

    alert(b);  // error: "b" is not defined
    let b = 0;
    
  • переменную «let» нельзя объявить повторно:

    «var»:

    var a;
    var a; // ок
    

    «let»:

    let b;
    let b; // error: "b" has already been declared
    
  • внутри цикла переменная «let» будет объявлена новая для каждой итерации:

    «var»:

    for (var i = 0; i < 10; i++) { /* … */ }
    alert(i); // 10
    

    «let»:

    for (let j = 0; j < 10; j++) { /* … */ }
    alert(j); // error: "j" is not defined
    

Вот вам следующее задание - угадайте значение x и y в следующем примере:

var x;
let y;
for (let y = 0; y < 10; y++) {
    x = y;
}
y = y ? x : 5;

Exercise
Correct!
False!
x = y =

Константы

В JavaScript до ES-2015 не было констант, но поскольку необходимость в них всё же была и до того, то была негласная договорённость: переменные, набранные в верхнем регистре через подчёркивание, не изменять:

var USER_STATUS_ACTIVE = 1;
var USER_STATUS_BANNED = 2;

Константы необходимы, чтобы избежать появления «magic numbers». Взгляните на следующий код «if(status==2)» — о чём тут речь, мало кому будет понятно, а вот код «if(status==USER_STATUS_BANNED)» уже более информативный.

Если же говорить об эре ES-2015, то тут уже используем «const», а об остальном уже позаботится сам JavaScript:

const USER_STATUS_ACTIVE = 1;
USER_STATUS_ACTIVE = 2; // error: assignment to constant variable

Да-да, я повторюсь, это наглядный пример правильного именования констант — имя однозначно указывает на хранимое значение — «статус активного пользователя».

Отдельно стоит заметить, константа не позволяет изменять саму переменную, но если мы присвоим константе объект или массив, то с ним вы сможете делать что душа пожелает:

const USER_STATUS_ACTIVE = 1;
const USER_STATUS_BANNED = 2;

const USER = {
    name: "mr.Smith",
    status: USER_STATUS_BANNED
};

USER.status = USER_STATUS_ACTIVE; // ok

USER = {name: "mr.Wesson"}; // error

Вот и получился «читаемый» код, мотайте на ус

Типы данных

В JavaScript не так уж и много типов данных:

  • number - целое или дробное число:

    var answer = 42;
    var pi = 3.1415;
    

    также существуют следующие специальные значения:

    • Infinity — за гранью 1.7976931348623157E+10308 (т.е. больше)
    • -Infinity — за гранью -1.7976931348623157E+10308 (т.е. меньше)
    • NaN (not-a-number) — результат числовой операции, которая завершилась ошибкой; для образца запустите следующий код в консоли:
      Math.sqrt(-5);
      
      но учтите – есть только один правильный способ проверки результата вычисления на NaN:
      isNaN(NaN);   // true
      
      и много неправильных:
      NaN == false; // false
      NaN == NaN;   // false
      if (NaN) {
      // данный блок никогда не выполнится
      }
      
  • string — строка, заключается в кавычки:

    var str = "Hello World!";
    

    В JavaScript нет разницы между двойными кавычками и одинарными, достаточно соблюдения их парности (привет PHP и Ruby).

  • boolean — булево значение, т.е. или «true» или «false»

    var result = true;
    
  • object — это объекты; на них остановлюсь подробнее чуть позже…

  • symbol — тип данных из ES-2015, служит для создания уникальных идентификаторов (о нём рассказа не будет, не в ходу ещё)
  • null — специальное значение для определения «пустоты»

    var result = null;
    
  • undefined — ещё одно специальное значение, для «неопределенности», используется как значение неопределённой или несуществующей переменной, например, если переменная объявлена, но значение ей ещё не присвоено:

    var a;
    // переменная есть, значения нет
    if (typeof a == "undefined") {
        alert("variable is undefined")
    }
    
    // переменной нет, совсем
    if (window["b"] == undefined) {
        alert("variable does not exist");
    }
    

    Во втором примере нас может ожидать сюрприз, если что-то определит переменную «undefined»; как обойти такую «неприятность», я ещё расскажу.

Хотел ещё акцентировать ваше внимание на приведение типов в JavaScript. Этот момент вызывает много вопросов у начинающих разработчиков, а ошибки связанные с ним будут преследовать вас первые полгода работы. Откройте страничку учебника об особенностях операторов, изучите её, а когда будете готовы переходите к выполнению следующего задания.

Посмотрите внимательно на код, и скажите - каков будет результат вычисления:

let x;
x = 42 + "x" + 42;
x = x/2 || x;

Exercise
Correct!
False!
x =

Массивы

Массив — это коллекция данных с числовыми индексами. Данные могут быть любого типа, в качестве примера я приведу один из самых простых вариантов — массив со строками:

//             0       1       2
var users = ["Ivan", "Petr", "Serg"]

Нумерация массивов начинается с «0», так что для получения первого элемента вам потребуется следующий код:

alert(users[0]); // выведет Ivan

Размер массива хранится в свойстве length:

alert(users.length); // выведет 3

users[3] = "Danylo";

alert(users.length); // выведет 4

В действительности «length» возвращает индекс последнего элемента массива+1, так что не попадитесь:

var a = [];

a[4] = 10;       // объявляем сразу пятый элемент

alert(a.length); // выведет 5;

Для перебора массива лучше всего использовать цикл «for(;;)»:

for (let i = 0; i < users.length; i++) {
    alert(users[i]); // последовательно выведет Ivan, Petr и Serg
}

На предыдущем примере цикл покажет четыре значения undefined, что может вызвать проблемы, и только затем будет работать со значением 10. Иначе действует похожий, но не равнозначный цикл for (in) (он сразу возьмётся за значение 10). Образец цикла:

for (let i in users) {
    alert(users[i]);
}

Для работы с последними элементами массива следует использовать методы «push()» и «pop()»:

users.push("Sidorov"); // добавляем элемент в конец массива

var sidorov = users.pop(); // удаляем и возращаем последний элемент

Для работы с первыми элементами массива следует использовать методы «unshift()» и «shift()»:

users.unshift("Sidorov"); // добавляем элемент в начало массива

var sidorov = users.shift(); // удаляем и возращаем первый элемент

Последние два метода работают медленно, т.к. перестраивают весь массив пошагово.

Упражнение для закрепления материала:

  • как мне получить пользователя по имени Andrey из массива users?
  • какова длина массива?
var users = new Array;
users.push("Anton");
users.push("Andrey");
users[100] = "Bogdan";
users.push("Boris");

Exercise
Correct!
False!
Andrey = length =

Функции

С функциями в JavaScript всё просто, вот вам элементарный пример:

function hello() {
    alert("Hello world");
}

Просто, пока не заговорить об анонимных функциях…

Анонимные функции

В JavaScript можно создать анонимную функцию (т.е. функцию без имени), для этого достаточно слегка изменить предыдущую конструкцию:

function() {
    alert("Hello world");
}

Так как функция — это вполне себе объект, то её можно присвоить переменной, и (или) передать в качестве параметра в другую функцию:

var myAlert = function(name) {
    alert("Hello, " + name);
}

function helloMike(myFunc) {  // тут функция передаётся как параметр
    myFunc("Mike");           // а тут мы её вызываем
}

helloMike(myAlert); // "Hello, Mike"

Анонимную функцию можно создать и тут же вызвать с необходимыми параметрами:

(function(name) {
    alert("Hello, " + name);
})("Mike");

Это несложно, скоро вы к ним привыкнете, и вам их будет недоставать в других языках.

Ах, этот ES-2015 – он принёс нам сокращенную запись для анонимных функций — «функции-стрелки»:

// была простая анонимная функция
var inc = function (x) {
    return x+1;
}

// стала запись в одну строчку
var inc = x => x+1;

// была функция с несколькими аргументами
var sum = function (a, b) {
    return a+b;
}

// стала запись в одну строчку
var sum = (a, b) => a+b;

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

Решите простую FizzBuzz-задачку:

Необходимо написать функцию, которая будет в качестве аргумента принимать число, если число кратно 3, то функция должна выводить Fizz, если число кратно 5, то Buzz, если число кратно и 3 и 5, то функция должна вернуть FizzBuzz

Exercise
Correct!
False!
function fizzBuzz(i) { }

Объекты

На объекты в JavaScript возложено две роли:

  • хранилище данных
  • функционал объекта

Первое предназначение можно описать следующим кодом:

var user = {
    name: "Ivan",
    age: 32
};

alert(user.name); // Ivan
alert(user.age); // 32

Это, фактически, реализация key-value хранилища, или хэша, или ассоциативного массива, или …. Ну, вы поняли, названий много. В JavaScript это объект, а запись выше – это JSON или JavaScript Object Notation (хоть и с небольшими оговорками).

Для перебора такого хранилища можно использовать цикл «for(.. in ..)»:

for (let prop in user) {
    alert(prop + "=" + user[prop]); // выведет name=Ivan
                                    // затем age=32
}

С объектами, конструкторами и т.д. в JavaScript посложнее будет, хотя для понимания не так уж много и надо. Запоминайте: любая функция, вызванная с использованием ключевого слова «new», возвращает нам объект, а сама становится конструктором данного объекта:

function User(name) {
    this.name = name;
    this.status = USER_STATUS_ACTIVE;
}

var me = new User("Anton");

Поведение функции «User()» при использовании «new» слегка изменится:

  1. Данная конструкция создаст новый, пустой объект
  2. Ключевое слово «this» получит ссылку на этот объект
  3. Функция выполнится и, возможно, изменит объект через «this» (как в примере выше)
  4. Функция вернёт «this» (по умолчанию)

Результатом выполнения кода будет следующий объект:

{
    "name": "Anton",
    "status": 1
}

Опять отправлю читать про ES-2015, в данном стандарте появилась конструкция «class», что по сути — синтаксический сахар для JavaScript — специально для тех, кто любит C-подобные языки программирования.

Простая задачка - нам нужен кот, и чтобы мы могли узнать какой он породы, и какого цвета:

Exercise
Correct!
False!
function Cat(breed, color) { } var cat = new Cat("British Shorthair", "silver"); cat.breed; cat.color;

Область видимости и чудо this

Для тех, кто только начинает своё знакомство с JavaScript я расскажу следующие нюансы:

  • когда вы объявляете переменную или функцию, то она становится частью «window»:
var a = 1234;

alert(window["a"]); // => 1234

function myLog(message) {
    alert(message); // => 1234
}

window["myLog"](a);
  • когда искомая переменная не найдена в текущей области видимости, её поиски будут продолжены в области видимости родительской функции:
var a = 1234;

(function(){
    var b = 4321;
    (function() {
        var c = 1111;
        alert((a+b)/c); // => 5
    })();
})();
  • чудо-переменная «this» всегда указывает на текущий объект, вызывающий функцию (поскольку по умолчанию все переменные и функции попадают в «window», то «this == window»):
var a = 1234;

function myLog() {
    alert(this);   // => window
    alert(this.a); // => 1234
}
  • контекст «this» можно изменить, используя функции «bind()», «call()», и «apply()»

Всё, что касается «window», относится лишь к браузерам, хотя поскольку книга о jQuery, то иное поведение я и не рассматриваю, но вот так прозрачно намекаю, что есть альтернативная реальность со своим «jQuery», и звать её там cheerio ;).

Замыкания

Изучив замыкания, можно понять много магии в JavaScript. Приведу пример кода с пояснениями:

var a = 1234;

var myFunc = function(){
    var b = 4321;
    var c = 1111;
    return function() {
        return ((a+b)/c);
    };
};

var anotherFunc = myFunc(); // myFunc возвращает анонимную функцию
                            // с «замкнутыми» значениями c и b

alert(anotherFunc()); // => 5

Что же тут происходит? Функция, объявленная внутри другой функции, имеет доступ к переменным родительской функции. Повтыкайте в код, пока вас не осенит, о чём я тут толкую.

Хорошая задачка, которая в полной мере даёт понимание сути проблемы: «Армия функций»

Рекомендуемые статьи по теме:

Вводная по JavaScript затянулась, лучше не поленитесь, и изучите весь учебник от Ильи Кантора.

results matching ""

    No results matching ""