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

415 lines
No EOL
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Основные операторы
Для работы с переменными, со значениями, JavaScript поддерживает все стандартные операторы, большинство которых есть и в других языках программирования.
[cut]
## Термины: "унарный", "бинарный", "операнд"
У операторов есть своя терминология, которая используется во всех языках программирования.
<ul>
<li>*Операнд* -- то, к чему применяется оператор. Например: `5 * 2` -- оператор умножения с левым и правым операндами. Другое название: "аргумент оператора".</li>
<li>*Унарным* называется оператор, который применяется к одному выражению. Например, оператор унарный минус `"-"` меняет знак числа на противоположный:
```js
//+ run
var x = 1;
alert( -x ); // -1, унарный минус
alert( -(x+2) ); // -3, унарный минус применён к результату сложения x+2
alert( -(-3) ); // 3
```
</li>
<li>*Бинарным* называется оператор, который применяется к двум операндам. Тот же минус существует и в бинарной форме:
```js
//+ run
var x = 1, y = 3;
alert( y - x ); // 2, бинарный минус
```
</li>
</ul>
Некоторые операторы, например, вычитание `"-"` и сложение `"+"`, бывают в двух вариантах: унарный -- при применении к одному операнду, и бинарный -- к двум.
## Арифметические операторы
**Базовые арифметические операторы знакомы нам с детства: это плюс `+`, минус `-`, умножить `*`, поделить `/`.**
Например:
```js
//+ run
alert(2 + 2); // 4
```
Или чуть сложнее:
```js
//+ run
var i = 2;
i = (2 + i) * 3 / i;
alert(i); // 6
```
**Более редкий арифметический оператор `%` интересен тем, что никакого отношения к процентам не имеет. Его результат `a % b` -- это остаток от деления `a` на `b`.**
Например:
```js
//+ run
alert(5 % 2); // 1, остаток от деления 5 на 2
alert(8 % 3); // 2, остаток от деления 8 на 3
alert(6 % 3); // 0, остаток от деления 6 на 3
```
### Сложение строк, бинарный +
Если бинарный оператор `+` применить к строкам, то он их объединяет в одну:
```js
var a = "моя" + "строка";
alert(a); // моястрока
```
**Если хотя бы один аргумент является строкой, то второй будет также преобразован к строке!**
Причем не важно, справа или слева находится операнд-строка, в любом случае нестроковый аргумент будет преобразован. Например:
```js
//+ run
alert( '1' + 2 ); // "12"
alert( 2 + '1' ); // "21"
```
Это приведение к строке -- особенность бинарного оператора `"+"`.
**Остальные арифметические операторы работают только с числами и всегда приводят аргументы к числу.**
Например:
```js
//+ run
alert( '1' - 2 ); // -1
alert( 6 / '2'); // 3
```
### Унарный плюс +
Унарный, то есть применённый к одному значению, плюс как арифметический оператор ничего не делает:
```js
//+ run
alert( +1 ); // 1
alert( +(1-2) ); // -1
```
Как видно, плюс ничего не изменил в выражениях. Результат -- такой же, как и без него.
Тем не менее, он широко применяется, так как его "побочный эффект" -- преобразование значения в число.
Например, у нас есть два числа, в форме строк, и нужно их сложить. Бинарный плюс сложит их как строки, поэтому используем унарный плюс, чтобы преобразовать к числу:
```js
//+ run
var a = "2";
var b = "3";
alert( a + b ); // "23", так как бинарный плюс складывает строки
alert( +a + b ); // "23", второй операнд - всё ещё строка
alert( +a + +b); // 5, число, так как оба операнда предварительно преобразованы в числа
```
## Присваивание
Оператор присваивания выглядит как знак равенства `=`:
```js
var i = 1 + 2;
alert(i); // 3
```
Он вычисляет выражение, которое находится справа, и присваивает результат переменной. Это выражение может быть достаточно сложным и включать в себя любые другие переменные:
```js
//+ run
var a = 1;
var b = 2;
*!*
a = b + a + 3; // (*)
*/!*
alert(a); // 6
```
В строке `(*)` сначала произойдет вычисление, использующее текущее значение `a` (т.е. `1`), после чего результат перезапишет старое значение `a`.
**Возможно присваивание по цепочке:**
```js
//+ 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`, а затем возвращает его. Благодаря этому присваивание можно использовать как часть более сложного выражения:
```js
//+ 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 -- гораздо больше операторов, поэтому существует целая [таблица приоритетов](https://developer.mozilla.org/en/JavaScript/Reference/operators/operator_precedence).
Она содержит как уже пройденные операторы, так и те, которые мы еще не проходили. В ней каждому оператору задан числовой приоритет. Тот, у кого число меньше -- выполнится раньше. Если приоритет одинаковый, то порядок выполнения -- слева направо.
Отрывок из таблицы:
<table>
<tr><td>...</td><td>...</td><td>...</td></tr>
<tr><td>5</td><td>умножение</td><td>`*`</td></tr>
<tr><td>5</td><td>деление</td><td>`/`</td></tr>
<tr><td>6</td><td>сложение</td><td>`+`</td></tr>
<tr><td>6</td><td>вычитание</td><td>`-`</td></tr>
<tr><td>17</td><td>присвоение</td><td>`=`</td></tr>
<tr><td>...</td><td>...</td><td>...</td></tr>
</table>
Посмотрим на таблицу в действии.
В выражении `x = 2 * 2 + 1` есть три оператора: присвоение `=`, умножение `*` и сложение `+`. Приоритет умножения `*` равен `5`, оно выполнится первым, затем произойдёт сложение `+`, у которого приоритет `6`, и после них -- присвоение `=`, с приоритетом 17.
## Инкремент/декремент: ++, --
Одной из наиболее частых операций в JavaScript, как и во многих других языках программирования, является увеличение или уменьшение переменной на единицу.
Для этого существуют даже специальные операторы:
<ul>
<li>**Инкремент** `++` увеличивает на 1:
```js
//+ run
var i = 2;
i++; // более короткая запись для i = i + 1.
alert(i); // 3
```
</li>
<li>**Декремент** `--` уменьшает на 1:
```js
//+ run
var i = 2;
i--; // более короткая запись для i = i - 1.
alert(i); // 1
```
</li>
</ul>
[warn]
Инкремент/декремент можно применить только к переменной.
Код `5++` даст ошибку.
[/warn]
Вызывать эти операторы можно не только после, но и перед переменной: `i++` (называется "постфиксная форма") или `++i` ("префиксная форма").
Обе эти формы записи делают одно и то же: увеличивают на `1`.
Тем не менее, между ними существует разница. Она видна только в том случае, когда мы хотим не только увеличить/уменьшить переменную, но и использовать результат в том же выражении.
Например:
```js
//+ run
var i = 1;
var a = ++i; // (*)
alert(a); // *!*2*/!*
```
В строке `(*)` вызов `++i` увеличит переменную, а *затем* вернёт ее значение в `a`. **То есть, в `a` попадёт значение `i` *после* увеличения**.
**Постфиксная форма `i++` отличается от префиксной `++i` тем, что возвращает старое значение, бывшее до увеличения.**
В примере ниже в `a` попадёт старое значение `i`, равное `1`:
```js
//+ run
var i = 1;
var a = i++; // (*)
alert(a); // *!*1*/!*
```
<ul>
<li>Если результат оператора не используется, а нужно только увеличить/уменьшить переменную -- без разницы, какую форму использовать:
```js
//+ run
var i = 0;
i++;
++i;
alert(i); // 2
```
</li>
<li>Если хочется тут же использовать результат, то нужна префиксная форма:
```js
//+ run
var i = 0;
alert( ++i ); // 1
```
</li>
<li>Если нужно увеличить, но нужно значение переменной *до увеличения* -- постфиксная форма:
```js
//+ run
var i = 0;
alert( i++ ); // 0
```
</li>
</ul>
**Инкремент/декремент можно использовать в любых выражениях.**
При этом он имеет более высокий приоритет и выполняется раньше, чем арифметические операции:
```js
//+ run
var i = 1;
alert( 2 * ++i ); // 4
```
```js
//+ run
var i = 1;
alert( 2 * i++ ); // 2, выполнился раньше но значение вернул старое
```
При этом, нужно с осторожностью использовать такую запись, потому что при чтении кода зачастую неочевидно, что переменая увеличивается. Три строки -- длиннее, зато нагляднее:
```js
//+ run
var i = 1;
alert( 2 * i );
i++;
```
## Побитовые операторы
Побитовые операторы рассматривают аргументы как 32-разрядные целые числа и работают на уровне их внутреннего двоичного представления.
Эти операторы не являются чем-то специфичным для JavaScript, они поддерживаются в большинстве языков программирования.
Поддерживаются следующие побитовые операторы:
<ul>
<li>AND(и) ( `&` )</li>
<li>OR(или) ( `|` )</li>
<li>XOR(побитовое исключающее или) ( `^` )</li>
<li>NOT(не) ( `~` )</li>
<li>LEFT SHIFT(левый сдвиг) ( `<<` )</li>
<li>RIGHT SHIFT(правый сдвиг) ( `>>` )</li>
<li>ZERO-FILL RIGHT SHIFT(правый сдвиг с заполнением нулями) ( `>>>` )</li>
</ul>
Вы можете более подробно почитать о них в отдельной статье [](/bitwise-operators).
## Вызов операторов с присваиванием
Часто нужно применить оператор к переменной и сохранить результат в ней же, например:
```js
var n = 2;
n = n + 5;
n = n * 2;
```
Эту запись можно укоротить при помощи совмещённых операторов: <code>+=, -=, *=, /=, &gt;&gt;=, &lt;&lt;=, &gt;&gt;&gt;=, &=, |=, ^=</code>.
Вот так:
```js
//+ run
var n = 2;
n += 5; // теперь n=7 (работает как n = n + 5)
n *= 2; // теперь n=14 (работает как n = n * 2)
alert(n); // 14
```
Все эти операторы имеют в точности такой же приоритет, как обычное присваивание, то есть выполняются после большинства других операций.
## Оператор запятая
Запятая тоже является оператором. Ее можно вызвать явным образом, например:
```js
//+ run
*!*
a = (5, 6);
*/!*
alert(a);
```
Запятая позволяет перечислять выражения, разделяя их запятой `','`. Каждое из них -- вычисляется и отбрасывается, за исключением последнего, которое возвращается.
Запятая -- единственный оператор, приоритет которого ниже присваивания. В выражении `a = (5,6)` для явного задания приоритета использованы скобки, иначе оператор `'='` выполнился бы до запятой `','`, получилось бы `(a=5), 6`.
Зачем же нужен такой странный оператор, который отбрасывает значения всех перечисленных выражений, кроме последнего?
Обычно он используется в составе более сложных конструкций, чтобы сделать несколько действий в одной строке. Например:
```js
// три операции в одной строке
for (*!*a = 1, b = 3, c = a*b*/!*; a < 10; a++) {
...
}
```
Такие трюки используются во многих JavaScript-фреймворках для укорачивания кода.