update
This commit is contained in:
parent
962caebbb7
commit
87bf53d076
1825 changed files with 94929 additions and 0 deletions
23
1-js/2-first-steps/8-operators/1-increment-order/solution.md
Normal file
23
1-js/2-first-steps/8-operators/1-increment-order/solution.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Разъяснения
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var a = 1, b = 1, c, d;
|
||||
|
||||
// префиксная форма сначала увеличивает a до 2, а потом возвращает
|
||||
c = ++a; alert(c); // 2
|
||||
|
||||
// постфиксная форма увеличивает, но возвращает старое значение
|
||||
d = b++; alert(d); // 1
|
||||
|
||||
// сначала увеличили a до 3, потом использовали в арифметике
|
||||
c = (2+ ++a); alert(c); // 5
|
||||
|
||||
// увеличили b до 3, но в этом выражении оставили старое значение
|
||||
d = (2+ b++); alert(d); // 4
|
||||
|
||||
// каждую переменную увеличили по 2 раза
|
||||
alert(a); // 3
|
||||
alert(b); // 3
|
||||
```
|
||||
|
20
1-js/2-first-steps/8-operators/1-increment-order/task.md
Normal file
20
1-js/2-first-steps/8-operators/1-increment-order/task.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Инкремент, порядок срабатывания
|
||||
|
||||
[importance 5]
|
||||
|
||||
Посмотрите, понятно ли вам, почему код ниже работает именно так?
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var a = 1, b = 1, c, d;
|
||||
|
||||
c = ++a; alert(c); // 2
|
||||
d = b++; alert(d); // 1
|
||||
|
||||
c = (2+ ++a); alert(c); // 5
|
||||
d = (2+ b++); alert(d); // 4
|
||||
|
||||
alert(a); // 3
|
||||
alert(b); // 3
|
||||
```
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
Ответ: `x = 5`.
|
||||
|
||||
Оператор присваивания возвращает значение, которое будет записано в переменную, например:
|
||||
|
||||
```js
|
||||
//+ run
|
||||
var a = 2;
|
||||
alert( a *= 2 ); // 4
|
||||
```
|
||||
|
||||
Отсюда `x = 1 + 4 = 5`.
|
12
1-js/2-first-steps/8-operators/2-assignment-result/task.md
Normal file
12
1-js/2-first-steps/8-operators/2-assignment-result/task.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Результат присваивания
|
||||
|
||||
[importance 3]
|
||||
|
||||
Чему будет равен `x` в примере ниже?
|
||||
|
||||
```js
|
||||
var a = 2;
|
||||
|
||||
var x = 1 + (a *= 2);
|
||||
```
|
||||
|
415
1-js/2-first-steps/8-operators/article.md
Normal file
415
1-js/2-first-steps/8-operators/article.md
Normal file
|
@ -0,0 +1,415 @@
|
|||
# Основные операторы
|
||||
|
||||
Для работы с переменными, со значениями, 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>+=, -=, *=, /=, >>=, <<=, >>>=, &=, |=, ^=</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-фреймворках для укорачивания кода.
|
Loading…
Add table
Add a link
Reference in a new issue