Всё вместе: особенности JavaScript

В этой главе приводятся основные особенности JavaScript, на уровне базовых конструкций, типов, синтаксиса.

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

Всё очень компактно, со ссылками на развёрнутые описания.

Структура кода

Операторы разделяются точкой с запятой:

alert('Привет'); alert('Мир');

Как правило, перевод строки тоже подразумевает точку с запятой. Так тоже будет работать:

alert('Привет')
alert('Мир')

…Однако, иногда JavaScript не вставляет точку с запятой. Например:

var a = 2
+3

alert(a); // 5

Бывают случаи, когда это ведёт к ошибкам, которые достаточно трудно найти и исправить, например:

alert("После этого сообщения будет ошибка")

[1, 2].forEach(alert)

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

Поэтому в JavaScript рекомендуется точки с запятой ставить. Сейчас это, фактически, общепринятый стандарт.

Поддерживаются однострочные комментарии // ... и многострочные /* ... */:

Подробнее: Структура кода.

Переменные и типы

  • Объявляются директивой var. Могут хранить любое значение:

    var x = 5;
    x = "Петя";
  • Есть 5 «примитивных» типов и объекты:

    x = 1;             // число
    x = "Тест";        // строка, кавычки могут быть одинарные или двойные
    x = true;          // булево значение true/false
    x = null;          // спец. значение (само себе тип)
    x = undefined;     // спец. значение (само себе тип)

    Также есть специальные числовые значения Infinity (бесконечность) и NaN.

    Значение NaN обозначает ошибку и является результатом числовой операции, если она некорректна.

  • Значение null не является «ссылкой на нулевой адрес/объект» или чем-то подобным. Это просто специальное значение.

    Оно присваивается, если мы хотим указать, что значение переменной неизвестно.

    Например:

    var age = null; // возраст неизвестен
  • Значение undefined означает «переменная не присвоена».

    Например:

    var x;
    alert( x ); // undefined

    Можно присвоить его и явным образом: x = undefined, но так делать не рекомендуется.

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

  • В имени переменной могут быть использованы любые буквы или цифры, но цифра не может быть первой. Символы доллар $ и подчёркивание _ допускаются наравне с буквами.

Подробнее: Переменные, Шесть типов данных, typeof.

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

Для того, чтобы интерпретатор работал в режиме максимального соответствия современному стандарту, нужно начинать скрипт директивой 'use strict';

'use strict';

...

Эта директива может также указываться в начале функций. При этом функция будет выполняться в режиме соответствия, а на внешний код такая директива не повлияет.

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

Взаимодействие с посетителем

Простейшие функции для взаимодействия с посетителем в браузере:

«prompt(вопрос[, по_умолчанию])»
Задать вопрос и возвратить введённую строку, либо null, если посетитель нажал «Отмена».
«confirm(вопрос)»
Задать вопрос и предложить кнопки «Ок», «Отмена». Возвращает, соответственно, true/false.
«alert(сообщение)»
Вывести сообщение на экран.

Все эти функции являются модальными, т.е. не позволяют посетителю взаимодействовать со страницей до ответа.

Например:

var userName = prompt("Введите имя?", "Василий");
var isTeaWanted = confirm("Вы хотите чаю?");

alert( "Посетитель: " + userName );
alert( "Чай: " + isTeaWanted );

Подробнее: Взаимодействие с пользователем: alert, prompt, confirm.

Особенности операторов

  • Для сложения строк используется оператор +.

    Если хоть один аргумент – строка, то другой тоже приводится к строке:

    alert( 1 + 2 ); // 3, число
    alert( '1' + 2 ); // '12', строка
    alert( 1 + '2' ); // '12', строка
  • Сравнение === проверяет точное равенство, включая одинаковый тип. Это самый очевидный и надёжный способ сравнения.

  • Остальные сравнения == < <= > >= осуществляют числовое приведение типа:

    alert( 0 == false ); // true
    alert( true > 0 ); // true

    Исключение – сравнение двух строк, которое осуществляется лексикографически (см. далее).

    Также: значения null и undefined при == равны друг другу и не равны ничему ещё. А при операторах больше/меньше происходит приведение null к 0, а undefined к NaN.

    Такое поведение может привести к неочевидным результатам, поэтому лучше всего использовать для сравнения с null/undefined оператор ===. Оператор == тоже можно, если не хотите отличать null от undefined.

    Например, забавное следствие этих правил для null:

    alert( null > 0 );  // false, т.к. null преобразовано к 0
    alert( null >= 0 ); // true, т.к. null преобразовано к 0
    alert( null == 0 ); // false, в стандарте явно указано, что null равен лишь undefined

    С точки зрения здравого смысла такое невозможно. Значение null не равно нулю и не больше, но при этом null >= 0 возвращает true!

  • Сравнение строк – лексикографическое, символы сравниваются по своим unicode-кодам.

    Поэтому получается, что строчные буквы всегда больше, чем прописные:

    alert( 'а' > 'Я' ); // true

    Подробнее: Основные операторы, Операторы сравнения и логические значения.

Логические операторы

В JavaScript есть логические операторы: И (обозначается &&), ИЛИ (обозначается ||) и НЕ (обозначается !). Они интерпретируют любое значение как логическое.

Не стоит путать их с побитовыми операторами И, ИЛИ, НЕ, которые тоже есть в JavaScript и работают с числами на уровне битов.

Как и в большинстве других языков, в логических операторах используется «короткий цикл» вычислений. Например, вычисление выражения 1 && 0 && 2 остановится после первого И &&, т.к. понятно что результат будет ложным (ноль интерпретируется как false).

Результатом логического оператора служит последнее значение в коротком цикле вычислений.

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

Например:

alert( 0 && 1 ); // 0
alert( 1 && 2 && 3 ); // 3
alert( null || 1 || 2 ); // 1

Подробнее: Логические операторы.

Циклы

  • Поддерживаются три вида циклов:

    // 1
    while (условие) {
      ...
    }
    
    // 2
    do {
      ...
    } while (условие);
    
    // 3
    for (var i = 0; i < 10; i++) {
      ...
    }
  • Переменную можно объявлять прямо в цикле, но видна она будет и за его пределами.

  • Поддерживаются директивы break/continue для выхода из цикла/перехода на следующую итерацию.

    Для выхода одновременно из нескольких уровней цикла можно задать метку.

    Синтаксис: «имя_метки:», ставится она только перед циклами и блоками, например:

    outer:
    for(;;) {
        ...
      for(;;) {
        ...
        break outer;
      }
    }

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

Подробнее: Циклы while, for.

Конструкция switch

При сравнениях в конструкции switch используется оператор ===.

Например:

var age = prompt('Ваш возраст', 18);

switch (age) {
  case 18:
    alert( 'Никогда не сработает' ); // результат prompt - строка, а не число

  case "18": // вот так - сработает!
    alert( 'Вам 18 лет!' );
    break;

  default:
    alert( 'Любое значение, не совпавшее с case' );
}

Подробнее: Конструкция switch.

Функции

Синтаксис функций в JavaScript:

// function имя(список параметров) { тело }
function sum(a, b) {
  var result = a + b;

  return result;
}

// использование:
alert( sum(1, 2) ); // 3
  • sum – имя функции, ограничения на имя функции – те же, что и на имя переменной.

  • Переменные, объявленные через var внутри функции, видны везде внутри этой функции, блоки if, for и т.п. на видимость не влияют.

  • Параметры копируются в локальные переменные a, b.

  • Функция без return считается возвращающей undefined. Вызов return без значения также возвращает undefined:

    function f() { }
    alert( f() ); // undefined

Подробнее: Функции.

Function Declaration и Expression

Функция в JavaScript является обычным значением.

Её можно создать в любом месте кода и присвоить в переменную, вот так:

var sum = function(a, b) {
  var result = a + b;

  return result;
}

alert( sum(1, 2) ); // 3

Такой синтаксис, при котором функция объявляется в контексте выражения (в данном случае, выражения присваивания), называется Function Expression, а обычный синтаксис, при котором функция объявляется в основном потоке кода – Function Declaration.

Функции, объявленные через Function Declaration, отличаются от Function Expression тем, что интерпретатор создаёт их при входе в область видимости (в начале выполнения скрипта), так что они работают до объявления.

Обычно это удобно, но может быть проблемой, если нужно объявить функцию в зависимости от условия. В этом случае, а также в других ситуациях, когда хочется создать функцию «здесь и сейчас», используют Function Expression.

Детали: Функциональные выражения.

Named Function Expression

Если объявление функции является частью какого-либо выражения, например var f = function... или любого другого, то это Function Expression.

В этом случае функции можно присвоить «внутреннее» имя, указав его после function. Оно будет видно только внутри этой функции и позволяет обратиться к функции изнутри себя. Обычно это используется для рекурсивных вызовов.

Например, создадим функцию для вычисления факториала как Function Expression и дадим ей имя me:

var factorial = function me(n) {
  return (n == 1) ? n : n * me(n - 1);
}

alert( factorial(5) ); // 120
alert( me ); // ошибка, нет такой переменной

Ограничение видимости для имени не работает в IE8-, но вызов с его помощью работает во всех браузерах.

Более развёрнуто: Именованные функциональные выражения.

Итого

В этой главе мы повторили основные особенности JavaScript, знание которых необходимо для обхода большинства «граблей», да и просто для написания хорошего кода.

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

Карта учебника

Комментарии

перед тем как писать…
  • Приветствуются комментарии, содержащие дополнения и вопросы по статье, и ответы на них.
  • Для одной строки кода используйте тег <code>, для нескольких строк кода — тег <pre>, если больше 10 строк — ссылку на песочницу (plnkr, JSBin, codepen…)
  • Если что-то непонятно в статье — пишите, что именно и с какого места.