Трагедия новичка: вынос переменных за циклы изменяет работу программы.
Всем привет. Я решил научиться в JS и стал проходить уроки по книге с этого сайта. Никаких проблем у меня не было и все шло хорошо до тех пор пока я не дошел до урока о выводе простых чисел из 88 страницы Современного учебника. Сам я совершенно не допетрил до того как по простому сделать эту штуку и посмотрел принцип решения. Решил сделать это не на циклах for а на циклах while. Итог: засел я на 2 часа и в конце концов впал в пучину отчаяния.:(
Однако, как мудрый и терпеливый воин, я не стал сразу забрасывать это дело, но начал по всякому пытаться понять - почему у меня не получается. Я насиловал себя и бедный JS: вставлял alert'ы для проверки переменных в начало и конец внешнего цикла, вставлял и во внутренний цикл вместо конструкции из if и continue. Это я делал для того, чтобы проверить тот факт, что первая переменная (i) всегда опережает внутреннюю (j) после первой интерации и цикл работает в таком темпе до самого конца. Эта битва шла долго, но ничего не работало как надо. В конце концов я решил вынести переменные из примера учебника за циклы и обнаружил что тогда все тоже перестает работать. Я был поражен. Я перестал понимать почему так происходит. Я... Отчаялся... Но друзья, объясните мне пожалуйста почему так происходит и что мне нужно почитать и выучить чтобы хорошенько это понять и осознать. Я не хочу оставаться тупым, поверженным долу и втоптанным в землю воином сим элементарным книжным примером.:help: Прошу вас сенъёры фронт-энда: помогите. Объясните доходчиво чем отличается правильная работа скрипта и как ведут себя в нем переменные от того, что сделал я. И можно ли мой вариант через while привести к рабочему виду. Примеры кода ниже: Рабочий пример из учебника:
let n = 10;
nextPrime: for (let i = 2; i <= n; i++) {
for (let j = 2; j < i; j++) {
if (i % j == 0) continue nextPrime;
}
alert(i);
}
Вот что сделал я (переменные ++i и ++j я тоже пытался размещать в разных местах):
let i = 2;
let j = 2;
butthurt: while (i <= 10) {
while (j < i) {
if (i % j == 0) continue butthurt;
++j;
}
alert(i);
++i;
}
Как я изменил пример из учебника, после чего он тоже перестал работать.
let n = 10;
let i = 2;
let j = 2
nextPrime: for (; i <= n; i++) {
for (; j < i; j++) {
if (i % j == 0) continue nextPrime;
}
alert(i);
}
|
И еще забыл написать: мне кажется, что неправильный цикл работает не так как правильный в том смысле, что внутренний цикл почему-то увеличивается попеременно со внешним и не прогоняется весь от 2 до 7 например когда значение i = 7 (то есть на 7 интерации внешнего цикла внутренний сразу начинает от 6 или 7 а не от 2-х). Но я не понимаю почему так происходит.
|
logicaface,
j никогда не уменьшается!!! а значит второй цикл не работает, как нужно. |
Цитата:
var i = 2;
butthurt: while (i <= 10) {
*!*
var j = 2;
*/!*
while (j < i) {
if (i % j == 0) {
*!*
++i;
*/!*
continue butthurt;
}
++j;
}
alert(i);
++i;
}
|
Цитата:
|
Спасибо вам большое за помощь. А можете еще, если не трудно объяснить почему пример из учебника перестал работать когда я вынес объявления переменных за циклы? В чем принципиальная разница между этим:
let n = 10;
nextPrime: for (let i = 2; i <= n; i++) {
for (let j = 2; j < i; j++) {
if (i % j == 0) continue nextPrime;
}
alert(i);
}
И между этим. И почему первое работает а второе нет.
let n = 10;
let i = 2;
let j = 2;
nextPrime: for (; i <= n; i++) {
for (; j < i; j++) {
if (i % j == 0) continue nextPrime;
}
alert(i);
}
|
Цитата:
ЗЫ А зачем их выносить надо было. Цикл for в js не так прост. Его совсем непросто проимитировать другими средствами в общем случае. |
logicaface, я х/з чего ты мутишь...
Но в первом варианте j всегда "начинается" с 2... А в твоем варианте она не "сбрасывается", всегда увеличивается на +1. Аналог правильного будет
let n = 10;
let i = 2;
nextPrime: for (; i <= n; i++) {
console.log('i', i)
let j = 2;
for (; j < i; j++) {
console.log('j', j)
if (i % j == 0) continue nextPrime;
}
console.log('end', i);
}
P.S. Всегда удивлялся как могут намутить кода некоторые товарищи... :D |
ksa, а i в первом варианте (рабочем) не всегда начинается с 2 с каждым новым включением continue? Там же тоже (внутри первого for стоит i = 2), значит когда continue скидывает интерацию из внутреннего цикла на внешний, то i тоже должно сбрасываться, или нет?) Я, походу, просто совсем не правильно понял как работают циклы...)))
|
continue передает управление на изменение переменной, а не на сброс.
Если бы в js был оператор goto, то цикл
for (i=0; i<n; i++) {
/*тело*/
}
можно было бы расписать так
i = 0;
goto LC;
LI:
i++;
LC:
if (i<n) goto LB;
goto LE;
LB:
{
//тело
}
goto LI;
LE:
|
voraa, я их выносил для того, чтобы сделать имитацию моих циклов на while. Мне ведь было интересно почему оно именно на while не работает. И вообще я хотел понять как ведут себя переменные в принципе. Я, выходит просто не до конца понял как работают циклы. Выходит значения циклов присваиваются заного только тогда, когда интерация полностью покидает цикл? J сбрасывается на 2 потому, что continue создает выход из внутреннего цикла а i не сбрасывается всегда на 2 потому, что из внешнего цикла никогда выхода во вне не происходит. Я правильно понял?)
|
voraa, все, я понял.) Спасибо вам большое что разжевали это все.)
|
Спасибо всем большое за помощь. Здорово, что тут такие отзывчивые люди.)
|
С помощью while можно имитировать, если нет continue.
Потому, что continue в while передает управление на проверку условия, а в for на изменение переменной. Если нет continue, то
for(i=0; i<n; i++){}
можно записать как
i=0;
while (i<10) {
....
i++;
}
|
voraa, я просто еще думал, что в цикле for изменение переменной происходит в самую самую последнюю очередь. Грубо говоря на самой последней. Другими словами я думал что когда срабатывает continue изменение переменной i не происходит, но происходит только после alert(i);
|
И то, где описана переменная, в цикле или во вне, тоже может иметь значение.
Сравните const ar = []; let i; for (i=0; i<5; i++) ar.push(() => i); alert (ar.map (f => f())); и const ar = []; for (let i=0; i<5; i++) ar.push(() => i); alert (ar.map (f => f())); |
voraa, Вот я не понимаю этого. Почему так происходит?
|
Цитата:
Поизучайте сами, что такое let, чем отличается от var, Особенности let в циклах. Про области видимости и замыкания. Тут https://learn.javascript.ru/ многое можно найти |
voraa, спасибо вам большое что так сильно помогли и указали где копать, хочется разобраться а не просто тупо сделать чтобы работало и забыть.
|
Цитата:
for (let ...)каждый раз для "блока" (цикла) создается новая переменная. Ведь ОВ let и const специально "ориентирована" на блоки. |
ksa, я пока совсем зеленый, это еще не понимаю. Буду читать, изучать. Благо, что уже есть какие-то подсказки.)
|
| Часовой пояс GMT +3, время: 01:35. |