This commit is contained in:
Ilya Kantor 2015-09-21 15:04:14 +02:00
parent f3886cfb79
commit 6baabac3c5
41 changed files with 196 additions and 163 deletions

View file

@ -1,5 +1,7 @@
The task demonstrates how postfix/prefix forms can lead to different results when used in comparisons.
<ol>
<li>**От 1 до 4**
<li>**From 1 to 4**
```js
//+ run
@ -7,13 +9,13 @@ var i = 0;
while (++i < 5) alert( i );
```
Первое значение: `i=1`, так как операция `++i` сначала увеличит `i`, а потом уже произойдёт сравнение и выполнение `alert`.
The first value is `i=1`, because `++i` first increments `i` and then returns the new value. So the first comparison is `1 < 5` and the `alert` shows `1`.
Далее `2,3,4..` Значения выводятся одно за другим. Для каждого значения сначала происходит увеличение, а потом -- сравнение, так как `++` стоит перед переменной.
Then follow `2,3,4…` -- the values show up one after another. The comparison always uses the incremented value, because `++` is before the variable.
При `i=4` произойдет увеличение `i` до `5`, а потом сравнение `while(5 < 5)` -- это неверно. Поэтому на этом цикл остановится, и значение `5` выведено не будет.
Finally, `i=4` is incremented to `5`, the comparison `while(5 < 5)` fails and the loop stops. So `5` is not shown.
</li>
<li>**От 1 до 5**
<li>**From 1 to 5**
```js
//+ run
@ -21,11 +23,15 @@ var i = 0;
while (i++ < 5) alert( i );
```
Первое значение: `i=1`. Остановимся на нём подробнее. Оператор `i++` увеличивает `i`, возвращая старое значение, так что в сравнении `i++ < 5` будет участвовать старое `i=0`.
The first value is again `i=1`. The postfix form of `i++` increments `i` and then returns the *old* value, so the comparison `i++ < 5` will use `i=0` (contrary to `++i < 5`).
Но последующий вызов `alert` уже не относится к этому выражению, так что получит новый `i=1`.
But the `alert` call is separate. It's another statement which executes after the increment and the comparison. So it gets the current `i=1`.
Далее `2,3,4..` Для каждого значения сначала происходит сравнение, а потом -- увеличение, и затем срабатывание `alert`.
Then follow `2,3,4…`
Окончание цикла: при `i=4` произойдет сравнение `while(4 < 5)` -- верно, после этого сработает `i++`, увеличив `i` до `5`, так что значение `5` будет выведено. Оно станет последним.</li>
Let's stop on `i=4`. The prefix form `++i` would increment it and use `5` in the comparison. But here we have the postfix form `i++`. So it increments `i` to `5`, but returns the old value. Hence the comparison is actually `while(4 < 5)` -- true, and the control goes on to `alert`.
The value `i=5` is the last one, because on the next step `while(5 < 5)` is false.
</li>
</ol>

View file

@ -1,10 +1,13 @@
# Какие значения i выведет цикл while?
# Which values shows the while?
[importance 4]
Для каждого цикла запишите, какие значения он выведет. Потом сравните с ответом.
For every loop, scribe down which values it shows, in your opinion.
And then compare with the answer.
<ol>
<li>Префиксный вариант
<li>The prefix form `++i`:
```js
var i = 0;
@ -12,7 +15,7 @@ while (++i < 5) alert( i );
```
</li>
<li>Постфиксный вариант
<li>The postfix form `i++`
```js
var i = 0;

View file

@ -1,4 +1,4 @@
**Ответ: от 0 до 4 в обоих случаях.**
**The answer: from `0` to `4` in both cases.**
```js
//+ run
@ -7,11 +7,13 @@ for (var i = 0; i < 5; ++i) alert( i );
for (var i = 0; i < 5; i++) alert( i );
```
Такой результат обусловлен алгоритмом работы `for`:
That can be easily deducted from the algorithm of `for`:
<ol>
<li>Выполнить присвоение `i=0`</li>
<li>Проверить `i<5`</li>
<li>Если верно - выполнить тело цикла `alert(i)`, затем выполнить `i++`</li>
<li>Execute once `i=0` before everything.</li>
<li>Check the condition `i<5`</li>
<li>If `true` -- execute the loop body `alert(i)`, and then `i++`</li>
</ol>
Увеличение `i++` выполняется отдельно от проверки условия (2), значение `i` при этом не используется, поэтому нет никакой разницы между `i++` и `++i`.
The increment `i++` is separated from the condition check (2). That's just another statement.
The value returned by the increment is not used here, so there's no difference between `i++` and `++i`.

View file

@ -1,17 +1,20 @@
# Какие значения i выведет цикл for?
# Which values get shown by the "for" loop?
[importance 4]
Для каждого цикла запишите, какие значения он выведет. Потом сравните с ответом.
For each loop scribe down which values it is going to show.
Then compare with the answer.
<ol>
<li>Постфиксная форма:
<li>The postfix form:
```js
for (var i = 0; i < 5; i++) alert( i );
```
</li>
<li>Префиксная форма:
<li>The prefix form:
```js
for (var i = 0; i < 5; ++i) alert( i );

View file

@ -9,4 +9,4 @@ for (var i = 2; i <= 10; i++) {
}
```
Чётность проверяется по остатку при делении на `2`, используя оператор "деление с остатком" `%`: `i % 2`.
We use the "modulo" `%` to get the remainder and check for the evenness here.

View file

@ -1,7 +1,7 @@
# Выведите чётные числа
# Output even numbers in the loop
[importance 5]
При помощи цикла `for` выведите чётные числа от `2` до `10`.
Use the `for` loop to output even numbers from `2` to `10`.
[demo /]

View file

@ -4,7 +4,7 @@
//+ run
var i = 0;
while (i < 3) {
alert( "номер " + i + "!" );
alert( `number ${i}!` );
i++;
}
```

View file

@ -1,13 +1,13 @@
# Замените for на while
# Replace "for" with "while"
[importance 5]
Перепишите код, заменив цикл `for` на `while`, без изменения поведения цикла.
Rewrite the code changing the `for` loop to `while` without altering it's behavior (the output should stay same).
```js
//+ run
for (var i = 0; i < 3; i++) {
alert( "номер " + i + "!" );
alert( `number ${i}!` );
}
```

View file

@ -1,18 +1,17 @@
```js
//+ run demo
var num;
do {
num = prompt("Введите число больше 100?", 0);
} while (num <= 100 && num != null);
num = prompt("Enter a number greater than 100?", 0);
} while (num <= 100 && num);
```
Цикл `do..while` повторяется, пока верны две проверки:
The loop `do..while` repeats while both checks are truthy:
<ol>
<li>Проверка `num <= 100` -- то есть, введённое число всё еще меньше `100`.</li>
<li>Проверка `num != null` -- значение `null` означает, что посетитель нажал "Отмена", в этом случае цикл тоже нужно прекратить.</li>
<li>The check for `num <= 100` -- that is, the entered value is still not greater than `100`.</li>
<li>The check for a truthiness of `num` checks that `num != null` and `num != ""` simultaneously.</li>
</ol>
Кстати, сравнение `num <= 100` при вводе `null` даст `true`, так что вторая проверка необходима.
P.S. By the way, if `num` is `null` then `num <= 100` would return `false`, not `true`!

View file

@ -1,11 +1,11 @@
# Повторять цикл, пока ввод неверен
# Repeat until the input is incorrect
[importance 5]
Напишите цикл, который предлагает `prompt` ввести число, большее `100`. Если посетитель ввёл другое число -- попросить ввести ещё раз, и так далее.
Write a loop which prompts for a number greater than `100`. If the visitor enters another number -- ask him to repeat the input, and so on.
Цикл должен спрашивать число пока либо посетитель не введёт число, большее `100`, либо не нажмёт кнопку Cancel (ESC).
The loop must ask for a number until either the visitor enters a number greater than `100` or cancels the input/enters an empty line.
Предполагается, что посетитель вводит только числа. Предусматривать обработку нечисловых строк в этой задаче необязательно.
Here we can assume that the visitor only inputs numbers. There's no need to implement the special handling for a non-numeric input in this task.
[demo /]

View file

@ -1,28 +1,29 @@
# Схема решения
There are many algorithms for this task.
Let's use a nested loop:
```js
Для всех i от 1 до 10 {
проверить, делится ли число i на какое - либо из чисел до него
если делится, то это i не подходит, берем следующее
если не делится, то i - простое число
For each i in the interval {
check if i has a divisor from 1..i
if yes => the value is not a prime
if no => the value is a prime, show it
}
```
# Решение
Решение с использованием метки:
The code using a label:
```js
//+ run
nextPrime:
for (var i = 2; i < 10; i++) {
for (var i = 2; i < 10; i++) { // for each i...
for (var j = 2; j < i; j++) {
if (i % j == 0) continue nextPrime;
}
alert( i ); // простое
for (var j = 2; j < i; j++) { // look for a divisor..
if (i % j == 0) continue nextPrime; // not a prime, go next i
}
alert( i ); // a prime
}
```
Конечно же, его можно оптимизировать с точки зрения производительности. Например, проверять все `j` не от `2` до `i`, а от `2` до квадратного корня из `i`. А для очень больших чисел -- существуют более эффективные специализированные алгоритмы проверки простоты числа, например [квадратичное решето](http://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%BA%D0%B2%D0%B0%D0%B4%D1%80%D0%B0%D1%82%D0%B8%D1%87%D0%BD%D0%BE%D0%B3%D0%BE_%D1%80%D0%B5%D1%88%D0%B5%D1%82%D0%B0) и [решето числового поля](http://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%89%D0%B8%D0%B9_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4_%D1%80%D0%B5%D1%88%D0%B5%D1%82%D0%B0_%D1%87%D0%B8%D1%81%D0%BB%D0%BE%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BF%D0%BE%D0%BB%D1%8F).
Surely, there's a lot of space to opimize it. Like, we could look for the divisors from `2` to square root of `i`. But anyway, if we want to be really efficient for large intervals, we need change the approach and rely heavily on advanced maths and algorithms like [Quadratic sieve](https://en.wikipedia.org/wiki/Quadratic_sieve), [General number field sieve](https://en.wikipedia.org/wiki/General_number_field_sieve) etc.

View file

@ -1,12 +1,16 @@
# Вывести простые числа
# Output prime numbers
[importance 3]
Натуральное число, большее 1, называется *простым*, если оно ни на что не делится, кроме себя и `1`.
An integer number greater than `1` is called a [prime](https://en.wikipedia.org/wiki/Prime_number) if it cannot be not divided without a remainder by anything except `1` and itself.
Другими словами, <code>n&gt;1</code> - простое, если при делении на любое число от `2` до `n-1` есть остаток.
In other words, `n>1` is a prime if the result of it's division by anything except `1` and `n` is not integer.
**Создайте код, который выводит все простые числа из интервала от `2` до `10`.** Результат должен быть: `2,3,5,7`.
For example, `5` is a prime, because it cannot be divided without a remainder by `2`, `3` and `4`.
P.S. Код также должен легко модифицироваться для любых других интервалов.
**Write the code which outputs prime numbers in the interval from `2` to `10`.**
The result will be `2,3,5,7`.
P.S. The code should be easily modifiable for other intervals.

View file

@ -1,21 +1,21 @@
Если совсем точно следовать условию, то сравнение должно быть строгим `'==='`.
To be precise, the `if` must use a strict comparison `'==='`.
В реальном случае, скорее всего, подойдёт обычное сравнение `'=='`.
In reality though, probably a simple `'=='` would do.
```js
//+ no-beautify
if(browser == 'IE') {
alert('О, да у вас IE!');
if(browser == 'Edge') {
alert("You've got the Edge!");
} else if (browser == 'Chrome'
|| browser == 'Firefox'
|| browser == 'Safari'
|| browser == 'Opera') {
alert('Да, и эти браузеры мы поддерживаем');
alert( 'Okay we support these browsers too' );
} else {
alert('Мы надеемся, что и в вашем браузере все ок!');
alert( 'We hope that this page looks ok!' );
}
```
Обратите внимание: конструкция `browser == 'Chrome' || browser == 'Firefox' ...` разбита на несколько строк для лучшей читаемости.
Please note: the construct `browser == 'Chrome' || browser == 'Firefox' …` is split into multiple lines for better readability.
Но всё равно запись через `switch` нагляднее.
But the `switch` is still neater and more descriptive.

View file

@ -1,24 +1,24 @@
# Напишите "if", аналогичный "switch"
# Rewrite the "switch" into an "if"
[importance 5]
Напишите `if..else`, соответствующий следующему `switch`:
Write the code using `if..else` which would correspond to the following `switch`:
```js
switch (browser) {
case 'IE':
alert( 'О, да у вас IE!' );
case 'Edge':
alert( "You've got the Edge!" );
break;
case 'Chrome':
case 'Firefox':
case 'Safari':
case 'Opera':
alert( 'Да, и эти браузеры мы поддерживаем' );
alert( 'Okay we support these browsers too' );
break;
default:
alert( 'Мы надеемся, что и в вашем браузере все ок!' );
alert( 'We hope that this page looks ok!' );
}
```

View file

@ -1,4 +1,4 @@
Первые две проверки -- обычный `case`, третья разделена на два `case`:
The first two checks are a usual `case`. The third one is split into two cases:
```js
//+ run
@ -22,6 +22,7 @@ switch (a) {
}
```
Обратите внимание: `break` внизу не обязателен, но ставится по "правилам хорошего тона".
Please note: the `break` at the bottom is not required. But we put it to make the code future-proof.
In the future, there is a chance that we'd want to add one more `case`, for example `case 4`. And if we forget to add a break before it, at the end of `case 3`, there will be an error. So that's a kind of self-insurance.
Допустим, он не стоит. Есть шанс, что в будущем нам понадобится добавить в конец ещё один `case`, например `case 4`, и мы, вполне вероятно, забудем этот `break` поставить. В результате выполнение `case 2`/`case 3` продолжится на `case 4` и будет ошибка.

View file

@ -1,8 +1,8 @@
# Переписать if'ы в switch
# Rewrite "if" into "switch"
[importance 4]
Перепишите код с использованием одной конструкции `switch`:
Rewrite the code below using a single `switch` statement:
```js
//+ run

View file

@ -1,12 +1,13 @@
# Конструкция switch
# The "switch" statement
Конструкция `switch` заменяет собой сразу несколько `if`.
A `switch` statement can replace multiple `if` checks.
It gives a more descriptive way to compare a value with multiple variants.
Она представляет собой более наглядный способ сравнить выражение сразу с несколькими вариантами.
[cut]
## Синтаксис
## The syntax
Выглядит она так:
It looks like this:
```js
//+ no-beautify
@ -26,22 +27,16 @@ switch(x) {
```
<ul>
<li>
Переменная `x` проверяется на строгое равенство первому значению `value1`, затем второму `value2` и так далее.
<li>The value of `x` is checked for a strict equality to the value from the first `case`, that is: `value1`, then to the second `value2` and so on.
</li>
<li>
Если соответствие установлено -- switch начинает выполняться от соответствующей директивы `case` и далее, *до ближайшего `break`* (или до конца `switch`).
</li>
<li>
Если ни один `case` не совпал -- выполняетcя (если есть) вариант `default`.
<li>If the equality is found -- `switch` starts to execute the code starting from the corresponding `case`, and to the nearest `break` (or to the end of `switch`).
</li>
<li>If no case matched then the `default` code is executed (if exists).</li>
</ul>
При этом `case` называют *вариантами `switch`*.
## An example
## Пример работы
Пример использования `switch` (сработавший код выделен):
An example of `switch` (the executed code is highlighted):
```js
//+ run
@ -49,28 +44,28 @@ var a = 2 + 2;
switch (a) {
case 3:
alert( 'Маловато' );
alert( 'Too small' );
break;
*!*
case 4:
alert( 'В точку!' );
alert( 'Exactly!' );
break;
*/!*
case 5:
alert( 'Перебор' );
alert( 'Too large' );
break;
default:
alert( 'Я таких значений не знаю' );
alert( "I don't know such values" );
}
```
Здесь оператор `switch` последовательно сравнит `a` со всеми вариантами из `case`.
Here the `switch` starts to compare `a` from the first `case` variant that is `3`. The match fails.
Сначала `3`, затем -- так как нет совпадения -- `4`. Совпадение найдено, будет выполнен этот вариант, со строки `alert('В точку!')` и далее, до ближайшего `break`, который прервёт выполнение.
Then `4`. That's the match, so the execution starts from `case 4` and till the nearest `break`.
**Если `break` нет, то выполнение пойдёт ниже по следующим `case`, при этом остальные проверки игнорируются.**
**If there is no `break` then the execution continues with the next `case` without any checks.**
Пример без `break`:
An example without `break`:
```js
//+ run
@ -78,36 +73,37 @@ var a = 2 + 2;
switch (a) {
case 3:
alert( 'Маловато' );
alert( 'Too small' );
*!*
case 4:
alert( 'В точку!' );
alert( 'Exactly!' );
case 5:
alert( 'Перебор' );
alert( 'Too big' );
default:
alert( 'Я таких значений не знаю' );
alert( "I don't know such values" );
*/!*
}
```
В примере выше последовательно выполнятся три `alert`:
In the example above we'll see sequential execution of three `alert`s:
```js
alert( 'В точку!' );
alert( 'Перебор' );
alert( 'Я таких значений не знаю' );
alert( 'Exactly!' );
alert( 'Too big' );
alert( "I don't know such values" );
```
В `case` могут быть любые выражения, в том числе включающие в себя переменные и функции.
[smart header="Any expresion can be a `switch/case` argument"]
Both `switch` and case allow arbitrary expresions.
Например:
For example:
```js
//+ run
var a = 1;
var a = "1";
var b = 0;
switch (a) {
switch (+a) {
*!*
case b + 1:
alert( 1 );
@ -115,72 +111,73 @@ switch (a) {
*/!*
default:
alert('нет-нет, выполнится вариант выше')
alert('no-no, see the code above, it executes');
}
```
[/smart]
## Группировка case
## Grouping of "case"
Несколько значений case можно группировать.
Several variants of `case` can be grouped.
For example, if we want the same code for `case 3` and `case 5`:
В примере ниже `case 3` и `case 5` выполняют один и тот же код:
```js
//+ run no-beautify
var a = 2+2;
var a = 2 + 2;
switch (a) {
case 4:
alert('Верно!');
alert('Right!');
break;
*!*
case 3: // (*)
case 5: // (**)
alert('Неверно!');
alert('Немного ошиблись, бывает.');
case 5:
alert('Wrong!');
alert('How about to take maths classes?');
break;
*/!*
default:
alert('Странный результат, очень странный');
alert('The result is strange. Really.');
}
```
При `case 3` выполнение идёт со строки `(*)`, при `case 5` -- со строки `(**)`.
The grouping is just a side-effect of how `switch/case` works without `break`. Here the execution of `case 3` starts from the line `(*)` and goes through `case 5`, because there's no `break`.
## Тип имеет значение
## The type matters
Let's emphase that the equality check is always strict. The values must be of the same type to match.
For example, let's consider the code:
Следующий пример принимает значение от посетителя.
```js
//+ run
var arg = prompt("Введите arg?")
var arg = prompt("Enter a value?")
switch (arg) {
case '0':
case '1':
alert( 'Один или ноль' );
alert( 'One or zero' );
case '2':
alert( 'Два' );
alert( 'Two' );
break;
case 3:
alert( 'Никогда не выполнится' );
alert( 'Never executes!' );
default:
alert('Неизвестное значение: ' + arg)
alert( 'An unknown value' )
}
```
Что оно выведет при вводе числа 0? Числа 1? 2? 3?
<ol>
<li>For `0`, `1`, the first `alert` runs.</li>
<li>For `2` the second `alert` runs.</li>
<li>But for `3`, the result of the `prompt` is a string `"3"`, which is not strictly equal `===` to the number `3`. So we've got a dead code in `case 3`! The `default` variant will execite.</li>
</ol>
Подумайте, выпишите свои ответы, исходя из текущего понимания работы `switch` и *потом* читайте дальше...
<ul>
<li>При вводе `0` выполнится первый `alert`, далее выполнение продолжится вниз до первого `break` и выведет второй `alert('Два')`. Итого, два вывода `alert`.</li>
<li>При вводе `1` произойдёт то же самое.</li>
<li>При вводе `2`, `switch` перейдет к `case '2'`, и сработает единственный `alert('Два')`.</li>
<li>**При вводе `3`, `switch` перейдет на `default`.** Это потому, что `prompt` возвращает строку `'3'`, а не число. Типы разные. Оператор `switch` предполагает строгое равенство `===`, так что совпадения не будет.</li>
</ul>

View file

@ -0,0 +1,5 @@
# Let, const and var revisited
Now as we know most language syntax constructs, let's recall `let`, `var` and `const` and make sure we understand the difference.

View file

@ -1,31 +1,37 @@
# Функции
# Functions
Зачастую нам надо повторять одно и то же действие во многих частях программы.
Quite often we need to perform a similar action in many places of the script.
Например, красиво вывести сообщение необходимо при приветствии посетителя, при выходе посетителя с сайта, ещё где-нибудь.
For example, we need to show a nice-looking message when a visitor logs in, logs out and maybe somewhere else.
Functions are the main "building blocks" of the program. They allow the code to be called many times without repetition.
Чтобы не повторять один и тот же код во многих местах, придуманы функции. Функции являются основными "строительными блоками" программы.
[cut]
Примеры встроенных функций вы уже видели -- это `alert(message)`, `prompt(message, default)` и `confirm(question)`. Но можно создавать и свои.
## Объявление
We've already seen examples of built-in functions, like `alert(message)`, `prompt(message, default)` and `confirm(question)`. But we can create functions of our own as well.
Пример объявления функции:
## Definition
An example of a function definition:
```js
function showMessage() {
alert( 'Привет всем присутствующим!' );
alert( 'Hello everyone!' );
}
```
Вначале идет ключевое слово `function`, после него *имя функции*, затем *список параметров* в скобках (в примере выше он пустой) и *тело функции* -- код, который выполняется при её вызове.
The `function` keyword goes first, then follows the *name of the function*, then a list of *parameters* in the brackets (empty in the example above) and finally the code of the function, also named "the function body".
Объявленная функция доступна по имени, например:
<img src="function_basics.png">
Once defined, the function can be called by it's name.
For instance:
```js
//+ run
function showMessage() {
alert( 'Привет всем присутствующим!' );
alert( 'Hello everyone!' );
}
*!*
@ -34,29 +40,35 @@ showMessage();
*/!*
```
Этот код выведет сообщение два раза. Уже здесь видна **главная цель создания функций: избавление от дублирования кода**.
The call executes the code of the function. Here we will see the message shown two times.
Если понадобится поменять сообщение или способ его вывода -- достаточно изменить его в одном месте: в функции, которая его выводит.
In this example we can see one of the main purposes of the functions: to evade code duplication.
## Локальные переменные
If we ever need to change the message or the way it is shown -- it's enough to modify the code in one place: the function which outputs it.
Функция может содержать *локальные* переменные, объявленные через `var`. Такие переменные видны только внутри функции:
## Local variables
A function may declare *local* variables with `var`, `let` or `const`.
These variables are only seen from inside the function:
```js
//+ run
function showMessage() {
*!*
var message = 'Привет, я - Вася!'; // локальная переменная
var message = "Hello, I'm JavaScript!"; // local variable
*/!*
alert( message );
}
showMessage(); // 'Привет, я - Вася!'
showMessage(); // Hello, I'm JavaScript!
alert( message ); // <-- будет ошибка, т.к. переменная видна только внутри
alert( message ); // <-- Error! The variable is local to the function
```
**Блоки `if/else`, `switch`, `for`, `while`, `do..while` не влияют на область видимости переменных.**
При объявлении переменной в таких блоках, она всё равно будет видна во всей функции.

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB