en.javascript.info/01-js/02-first-steps/08-operators/article.md
Ilya Kantor f301cb744d init
2014-10-26 22:10:13 +03:00

17 KiB
Raw Blame History

Основные операторы

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

Термины: "унарный", "бинарный", "операнд"

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

  • *Операнд* -- то, к чему применяется оператор. Например: `5 * 2` -- оператор умножения с левым и правым операндами. Другое название: "аргумент оператора".
  • *Унарным* называется оператор, который применяется к одному выражению. Например, оператор унарный минус `"-"` меняет знак числа на противоположный:
    //+ run
    var x = 1;
    alert( -x );     // -1, унарный минус
    alert( -(x+2) ); // -3, унарный минус применён к результату сложения x+2
    alert( -(-3) );  // 3
    
  • *Бинарным* называется оператор, который применяется к двум операндам. Тот же минус существует и в бинарной форме:
    //+ run
    var x = 1, y = 3;
    alert( y - x ); // 2, бинарный минус
    

Некоторые операторы, например, вычитание "-" и сложение "+", бывают в двух вариантах: унарный -- при применении к одному операнду, и бинарный -- к двум.

Арифметические операторы

Базовые арифметические операторы знакомы нам с детства: это плюс +, минус -, умножить *, поделить /.

Например:

//+ run
alert(2 + 2); // 4

Или чуть сложнее:

//+ run
var i = 2;

i = (2 + i) * 3 / i; 

alert(i); // 6

Более редкий арифметический оператор % интересен тем, что никакого отношения к процентам не имеет. Его результат a % b -- это остаток от деления a на b.

Например:

//+ run
alert(5 % 2); // 1, остаток от деления 5 на 2 
alert(8 % 3); // 2, остаток от деления 8 на 3
alert(6 % 3); // 0, остаток от деления 6 на 3

Сложение строк, бинарный +

Если бинарный оператор + применить к строкам, то он их объединяет в одну:

var a = "моя" + "строка";
alert(a); // моястрока

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

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

//+ run
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"

Это приведение к строке -- особенность бинарного оператора "+".

Остальные арифметические операторы работают только с числами и всегда приводят аргументы к числу.

Например:

//+ run
alert( '1' - 2 ); // -1
alert( 6 / '2'); // 3

Унарный плюс +

Унарный, то есть применённый к одному значению, плюс как арифметический оператор ничего не делает:

//+ run
alert( +1 ); // 1
alert( +(1-2) ); // -1

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

Тем не менее, он широко применяется, так как его "побочный эффект" -- преобразование значения в число.

Например, у нас есть два числа, в форме строк, и нужно их сложить. Бинарный плюс сложит их как строки, поэтому используем унарный плюс, чтобы преобразовать к числу:

//+ run
var a = "2";
var b = "3";

alert( a + b ); // "23", так как бинарный плюс складывает строки
alert( +a + b ); // "23", второй операнд - всё ещё строка

alert( +a + +b); // 5, число, так как оба операнда предварительно преобразованы в числа

Присваивание

Оператор присваивания выглядит как знак равенства =:

var i = 1 + 2;

alert(i); // 3

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

//+ run
var a = 1;
var b = 2;

*!*
a = b + a + 3;  // (*)
*/!*

alert(a); // 6

В строке (*) сначала произойдет вычисление, использующее текущее значение a (т.е. 1), после чего результат перезапишет старое значение a.

Возможно присваивание по цепочке:

//+ run
var a, b, c;

*!*
a = b = c = 2 + 2;
*/!*

alert(a); // 4
alert(b); // 4
alert(c); // 4

Такое присваивание работает справа-налево, то есть сначала вычислятся самое правое выражение 2+2, присвоится в c, затем выполнится b = c и, наконец, a = b.

[smart header="Оператор \"=\" возвращает значение"] Все операторы возвращают значение. Вызов x = выражение записывает выражение в x, а затем возвращает его. Благодаря этому присваивание можно использовать как часть более сложного выражения:

//+ run
var a = 1;
var b = 2;

*!*
var c = 3 - (a = b + 1);
*/!*

alert(a); // 3
alert(c); // 0

В примере выше результатом (a = b + 1) является значение, которое записывается в a (т.е. 3). Оно используется для вычисления c.

Забавное применение присваивания, не так ли?

Знать, как это работает -- стоит обязательно, а вот писать самому -- только если вы уверены, что это сделает код более читаемым и понятным. [/smart]

Приоритет

В том случае, если в выражении есть несколько операторов - порядок их выполнения определяется приоритетом.

Из школы мы знаем, что умножение в выражении 2 * 2 + 1 выполнится раньше сложения, т.к. его приоритет выше, а скобки явно задают порядок выполнения. Но в JavaScript -- гораздо больше операторов, поэтому существует целая таблица приоритетов.

Она содержит как уже пройденные операторы, так и те, которые мы еще не проходили. В ней каждому оператору задан числовой приоритет. Тот, у кого число меньше -- выполнится раньше. Если приоритет одинаковый, то порядок выполнения -- слева направо.

Отрывок из таблицы:

.........
5умножение`*`
5деление`/`
6сложение`+`
6вычитание`-`
17присвоение`=`
.........

Посмотрим на таблицу в действии.

В выражении x = 2 * 2 + 1 есть три оператора: присвоение =, умножение * и сложение +. Приоритет умножения * равен 5, оно выполнится первым, затем произойдёт сложение +, у которого приоритет 6, и после них -- присвоение =, с приоритетом 17.

Инкремент/декремент: ++, --

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

Для этого существуют даже специальные операторы:

  • **Инкремент** `++` увеличивает на 1:
    //+ run
    var i = 2;
    i++;      // более короткая запись для i = i + 1.
    alert(i); // 3
    
  • **Декремент** `--` уменьшает на 1:
    //+ run
    var i = 2;
    i--;      // более короткая запись для i = i - 1.
    alert(i); // 1
    

[warn] Инкремент/декремент можно применить только к переменной. Код 5++ даст ошибку. [/warn]

Вызывать эти операторы можно не только после, но и перед переменной: i++ (называется "постфиксная форма") или ++i ("префиксная форма").

Обе эти формы записи делают одно и то же: увеличивают на 1.

Тем не менее, между ними существует разница. Она видна только в том случае, когда мы хотим не только увеличить/уменьшить переменную, но и использовать результат в том же выражении.

Например:

//+ run
var i = 1;
var a = ++i; // (*)

alert(a); // *!*2*/!*

В строке (*) вызов ++i увеличит переменную, а затем вернёт ее значение в a. То есть, в a попадёт значение i после увеличения.

Постфиксная форма i++ отличается от префиксной ++i тем, что возвращает старое значение, бывшее до увеличения.

В примере ниже в a попадёт старое значение i, равное 1:

//+ run
var i = 1;
var a = i++; // (*)

alert(a); // *!*1*/!*
  • Если результат оператора не используется, а нужно только увеличить/уменьшить переменную -- без разницы, какую форму использовать:
    //+ run
    var i = 0;
    i++; 
    ++i; 
    alert(i); // 2
    
  • Если хочется тут же использовать результат, то нужна префиксная форма:
    //+ run
    var i = 0;
    alert( ++i ); // 1
    
  • Если нужно увеличить, но нужно значение переменной *до увеличения* -- постфиксная форма:
    //+ run
    var i = 0;
    alert( i++ ); // 0
    

Инкремент/декремент можно использовать в любых выражениях.

При этом он имеет более высокий приоритет и выполняется раньше, чем арифметические операции:

//+ run
var i = 1;
alert( 2 * ++i ); // 4
//+ run
var i = 1;
alert( 2 * i++ ); // 2, выполнился раньше но значение вернул старое

При этом, нужно с осторожностью использовать такую запись, потому что при чтении кода зачастую неочевидно, что переменая увеличивается. Три строки -- длиннее, зато нагляднее:

//+ run
var i = 1;
alert( 2 * i );
i++;

Побитовые операторы

Побитовые операторы рассматривают аргументы как 32-разрядные целые числа и работают на уровне их внутреннего двоичного представления.

Эти операторы не являются чем-то специфичным для JavaScript, они поддерживаются в большинстве языков программирования.

Поддерживаются следующие побитовые операторы:

  • AND(и) ( `&` )
  • OR(или) ( `|` )
  • XOR(побитовое исключающее или) ( `^` )
  • NOT(не) ( `~` )
  • LEFT SHIFT(левый сдвиг) ( `<<` )
  • RIGHT SHIFT(правый сдвиг) ( `>>` )
  • ZERO-FILL RIGHT SHIFT(правый сдвиг с заполнением нулями) ( `>>>` )

Вы можете более подробно почитать о них в отдельной статье .

Вызов операторов с присваиванием

Часто нужно применить оператор к переменной и сохранить результат в ней же, например:

var n = 2;
n = n + 5;  
n = n * 2;

Эту запись можно укоротить при помощи совмещённых операторов: +=, -=, *=, /=, >>=, <<=, >>>=, &=, |=, ^=.

Вот так:

//+ run
var n = 2;
n += 5; // теперь n=7 (работает как n = n + 5)
n *= 2; // теперь n=14 (работает как n = n * 2)

alert(n); // 14

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

Оператор запятая

Запятая тоже является оператором. Ее можно вызвать явным образом, например:

//+ run
*!*
a = (5, 6);
*/!*

alert(a);

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

Запятая -- единственный оператор, приоритет которого ниже присваивания. В выражении a = (5,6) для явного задания приоритета использованы скобки, иначе оператор '=' выполнился бы до запятой ',', получилось бы (a=5), 6.

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

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

// три операции в одной строке
for (*!*a = 1, b = 3, c = a*b*/!*; a < 10; a++) {
 ...
}

Такие трюки используются во многих JavaScript-фреймворках для укорачивания кода.