Основы JavaScript 4.1. Встроенные инструменты

Работа со строками

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

var language = 'javascript';
alert(language.length); // 10
language.length = 3;
alert(language.length); // 10, нельзя изменить длину
alert(language[0]); // "j", отсчет символов начинается с нуля

Для работы со строками в JavaScript существуют следующие методы:

charAt(n) возвращает символ с индексом n. Аналог [n]
charCodeAt(n) возвращает Unicode-код символа в позиции n
String.fromCharCode(code) возвращает символ по его Unicode-коду code
indexOf(subString [, start]) возвращает позицию найденной подстроки или -1, если подстрока не найдена. В start можно указать, с какой позиции начинать поиск
toUpperCase() перевод строки в верхний регистр
toLowerCase() перевод строки в нижний регистр
substr(start [, size]) возвращает подстроку, начинающуюся со start, и размером size или до конца строки
substring(start [, finish]) возвращает подстроку, начинающуюся со start, и до finish, не включая её, или до конца строки. Индексы, выходящие за диапазон строки урезает, при finish < start меняет аргументы местами
slice(start [, finish]) работает аналогично substring, но отрицательные индексы отсчитываются с конца строки

Работа с числами

Способы записи чисел:

Особенностью чисел в Javascript является неточность вычислений (например, 0.1 + 0.2 != 0.3), связанная с тем, что некоторые дробные числа не могут быть представлены в двоичной системе в виде конечной дроби. Следует помнить об этом и по возможности избегать требующих точности вычислений с дробными числами, заменяя их на операции с целыми.

Для работы с числами в JavaScript существуют следующие функции и методы:

isNaN(n) проверяет n на NaN
isFinite(n) проверяет, конечно ли n. Возвращает false для Infinity, -Infinity и NaN
parseInt(n [, base]) посимвольно преобразует n в целое число. Если указан base, то интерпретирует n как число в base-ричной системе исчисления. base должно быть больше в пределах 2..36, иначе вернётся NaN
parseFloat(n) посимвольно преобразует n в число с дробной частью
.toString(base) преобразует число в строку-число в base-ричной системе исчисления. base должно быть больше в пределах 2..36, иначе сгенерируется ошибка
.toFixed(precision) возвращает строку-число, округленное до precision знаков после запятой. Если значимых значений нет, то дополняет нулями

Математические функции

Для выполнения математических операций используются методы специального объекта Math:

floor(n) округляет n до целого вниз
ceil(n) округляет n до целого вверх
round(n) округляет n до целого по правилам округления
abs(n) вычисляет абсолютное значение для n
sin(angle) вычисляет синус угла angle, заданного в радианах
cos(angle) вычисляет косинус угла angle, заданного в радианах
tan(angle) вычисляет тангенс угла angle, заданного в радианах
asin(n вычисляет арксинус n
acos(n вычисляет арккосинус n, результат в раианах
atan(n) вычисляет арктангенс n
atan2(x, y) вычисляет угол до точки (x, y)
min(e1, e2, ...) возвращает минимальное значение из аргументов
max(e1, e2, ...) возвращает максимальное значение из аргументов
pow(n, exp) вычисляет n в степени exp
sqrt(n) вычисляет квадратный корень из n
log(n) вычисляет натуральный логарифм от n
exp(n) вычисляет e (экспонента) в степени n
random() возвращает псевдослучайное число в диапазоне [0;1)

Объект Math также содержит в себе математические константы:

и некоторые заранее вычисленные величины:

Работа с датой и временем

Работы с датой и временем в JavaScript осуществляется при помощи объекта Date:

// получаем объект текущего момента времени
var dateNow = new Date();
alert(dateNow); //

// получаем текущий timestamp в миллисекундах
var dateNow2 = Date.now();
alert(dateNow2); //

// задаем дату в виде миллисекунд, прошедших после после 1 января 1970 года
var dateMilliseconds = new Date(60 * 1000);
alert(dateMilliseconds); // Thu Jan 01 1970 02:01:00 GMT+0200 (MSK)

// задаем дату в виде строки в формате RFC2822
var dateString = new Date("Wed Oct 11 2017 12:00:00 GMT+0300 (EEST)");
alert(dateString); // Wed Oct 11 2017 12:00:00 GMT+0300 (EEST)

// задаем дату в виде строки в формате ISO 8601 Extended
var dateString2 = new Date("2017-10-12T19:30:00+03:00");
alert(dateString2); // Thu Oct 12 2017 19:30:00 GMT+0300 (EEST)

// задаем дату в виде массива в формате год, месяц, число, часы, минуты, секунды
var dateArguments = new Date(2018, 0, 1, 12, 0, 0);
alert(dateArguments); // Mon Jan 01 2018 12:00:00 GMT+0200 (MSK)

Работа с JSON

JSON — универсальный формат хранения данных. Для работы с этим форматом в JavaScript используют объект JSON с двумя методами: для извлечения данных из JSON и для преобразования данных в JSON.

// извлечение данных
var fromJsonString = '[1, "a", {"b": 2}]';
var fromJsonObject = JSON.parse(fromJsonString); // в переменную попадает распаршенный массив [1, "a", {"b": 2}]

С помощью второго наобязательного параметра-функции можно при парсинге обрабатывать свойства результирующего объекта:

var fromJsonString2 = '{"integer": 1.1, "float": 2.2, "more": {"integer": 3.3}}';
var fromJsonObject2 = JSON.parse(fromJsonString2, function (key, value) {
    if(key=="integer") {
        return parseInt(value);
    }
    return value;
});
// fromJsonObject2={integer: 1, float: 2.2, more: {integer: 3}}

Данная функция работает рекурсивно, т.е. преобразуются все совпадения свойств, в т.ч. и вложенных.

Для отправки на сервер, сохранения в localStorage и т.д. используют преобразование данных в JSON-строку с помощью метода stringify. Такой процесс называется сериализацией

var toJsonObject = {"name": "Bill", "age": 42};
var toJsonString = JSON.stringify(toJsonObject);
// toJsonString = '{"name":"Bill","age":42}'

С помощью второго необязательного параметра можно указать (с помощью массива или функции), какие свойства необходимо сериализовать.

var toJsonObject2 = {"name": "Bill", "age": 42};
var toJsonString2 = JSON.stringify(toJsonObject, ["name"]);
// toJsonString2 = '{"name":"Bill"}'

Третий необзательный параметр метода stringify позволяет отформатировать выходную строку, добавив указанное количество пробелов или указанную строку

var toJsonObject3 = {"name": "Bill", "age": 42};
var toJsonString3 = JSON.stringify(toJsonObject, "", 4);
/* toJsonString3 =
{
    "name": "Bill",
    "age": 42
}
*/

Строгий режим use strict

В своем развитии JavaScript, при введнии новых возможностей, старался максимально сохранить совместимость старого кода. До того момента, когда синтаксис привели к стардантизированному виду, было написано столько сайтов, использующих устаревшие возможности или устаревший синтаксис, что нельзя было просто отказаться от этого старого кода. Потому в ES5 была введена специальная директива use strict, которая показывает интерпретатору, что использующий ее код написан с соблюдением стандартов.

"use strict";
// вызовет ошибку при попытке создания переменной без var
myVar = 0;

// вызовет ошибку при попытке использования with
var user = {};
with(user) {
    name = "Petro";
}

// вызовет ошибку при попытке объявить свойство более 1 раза
user = {
    name: "Ivan",
    name: "Petro"
};

// вызовет ошибку при попытке создания функции с одинаковыми параметрами
function rename(name, name, surName) {
    "use strict";
    this.name = name;
    this.surName = surName;
}

// вызовет ошибку при попытке использования чисел в восьмиричной нотации
var today = 013;

Куки

Куки — это текстовые файлы, которые сайты сохраняют на компьютере пользователя. При повторном заходе на сайт последний может "узнать" пользователя по содержимому куки.

В JavaScript куки доступны через document.cookie. При обращении к этому свойству оно выводит строку, в которой переменные перечислены через точку с запятой (;), название переменной и ее значение разделены знаком равно (=). При присваивании document.cookie строки создается новая переменная и добавляется в конец списка куки.

alert(document.cookie); // test=test; test2=test; test3=test
document.cookie = "test4=test";
alert(document.cookie); // test=test; test2=test; test3=test; test4=test

Так как при чтении куки стоит задача получения значения конкретной переменной, то приходится либо писать дополнительный код для парсинга document.cookie, либо воспользоваться готовой функцией:

function getCookie(name) {
    var matches = document.cookie.match(new RegExp(
        "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
    ));
    return matches ? decodeURIComponent(matches[1]) : undefined;
}

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

function setCookie(name, value, options) {
    options = options || {};

    var expires = options.expires;

    if (typeof expires == "number" && expires) {
        var d = new Date();
        d.setTime(d.getTime() + expires * 1000);
        expires = options.expires = d;
    }
    if (expires && expires.toUTCString) {
        options.expires = expires.toUTCString();
    }

    value = encodeURIComponent(value);

    var updatedCookie = name + "=" + value;

    for (var propName in options) {
        updatedCookie += "; " + propName;
        var propValue = options[propName];
        if (propValue !== true) {
            updatedCookie += "=" + propValue;
        }
    }

    document.cookie = updatedCookie;
}

Функция принимает три параметра: имя переменной, значение и опции. В опциях указывается домен (domain) и путь (path), для которых доступна переменная, время жизни (expires) и доступ по https (secure).

Ошибки и их обработка

В программировании на JavaScript существует три типа ошибок:

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

Основные типы ошибок

Перехват ошибок

Перехват ошибок осуществляется с помощью конструкции try..catch

try {
    bad_code();
} catch(e) {
    console.log("Возникла ошибка ", e);
}

Использование try..catch позволяет избежать полного прекращения работы скрипта, т.е. если ошибка возникла внутри этого блока, то код за пределами блока продолжит выполнение. Перехват возможен только для ошибок времени выполнения, синтаксические ошибки прекратят работу скрипта в любом случае.

Нет необходимости заворачивать вызов каждой функции в try..catch. Используйте её только в тех случаях, если предполагается изменение поведения функции, чтобы это изменение не вызвало поломку всей программы, либо тогда, когда вы не можете быть уверены в содержимом каких-либо объектов, например, при манипуляции с элементами DOM на странице, получении данных с сервера или пользовательского ввода.

Информация об ошибке

При возникновении ошибки в блок catch попадает объект ошибки под именем, указанным в качестве аргумента. Если блок обработки ошибки не содержит никакой сложной логики и большого количества строк кода, то в качестве имени аргумента допустимо использовать просто e. Для примера выше объект ошибки будет иметь следующий вид:

{
    name: "ReferenceError",
    message: "bad_code is not defined",
    stack: "ReferenceError: bad_code is not defined↵ at file:///.../javascript_4/index_1.html:370:5"
}

В свойстве name содержится тип ошибки, в message — содержимое ошибки, а в stack — порядок вызова функций до возникновения ошибки, а также название файла и номер строки кода, вызвавшего возникновение ошибки.

Блок finally

У конструкции try..catch есть необязаетльный блок finally, используемый для кода, который должен выполниться независимо от того, возникла ошибка или нет. Синтаксис:

try {
    bad_code();
} catch(e) {
    console.log("Возникла ошибка ", e);
} finally {
    console.log("Вот так вот");
}

Поведение "выполниться в любом случае" справедливо даже для случаев, когда блок try..catch находится в какой-то функции и внутри блока есть return.

function provideData() {
    var connect;
    try {
        connect = server.connect();
        var data = connect.getData();
        return data;
    } catch(e) {
        console.log("Can`t get data from server");
    } finally {
        connect.close();
    }
}

Использование собственных ошибок

При обработке ошибок, связанных с обработкой "внешних" данных (данные сервера, пользовательский ввод, DOM-элементы страницы) может возникнуть необходимость сгенерировать собственную ошибку для дальнейшего проброса обработчику ошибок. Для этого используют оператор throw. Для корректной обработки ошибки в качестве аргумента для throw передают объект ошибки, который можно создать либо с помощью конструктора Error, либо с помощью более специфических конструкторов SyntaxError, ReferenceError, RangeError:

throw new Error("Data is wrong!");

Регулярные выражения

Регулярные выражения — мощное средство поиска строк.

Для регулярных выражений используются:

Флаги: