for
Baseline Широко доступно
Эта функция хорошо зарекомендовала себя и работает на многих устройствах и версиях браузеров. Она доступна во всех браузерах с июля 2015 года.
Инструкция for создает цикл, состоящий из трех необязательных выражений, заключенных в скобки и разделенных точками с запятой, за которыми следует инструкция (обычно инструкция-блок), которая будет выполняться в цикле.
Попробуйте
let str = "";
for (let i = 0; i < 9; i++) {
str += i;
}
console.log(str);
// Expected output: "012345678"
Синтаксис
for (initialization; condition; afterthought) statement
-
initializationНеобязательно -
Выражение (включая выражения присваивания) или объявление переменной, вычисляемое один раз перед началом цикла. Обычно используется для инициализации переменной-счетчика. Это выражение может опционально объявлять новые переменные с ключевыми словами
varилиlet. Переменные, объявленные с помощьюvar, не являются локальными для цикла, то есть они находятся в той же области видимости, что и сам циклfor. Переменные, объявленные с помощьюlet, являются локальными для инструкции.Результат этого выражения отбрасывается.
-
conditionНеобязательно -
Выражение, которое будет вычисляться перед каждой итерацией цикла. Если это выражение вычисляется как true, выполняется
statement. Если выражение вычисляется как false, выполнение цикла завершается, и управление передается первой инструкции после конструкцииfor.Этот условный тест необязателен. Если он опущен, условие всегда вычисляется как true.
-
afterthoughtНеобязательно - Выражение, которое будет вычисляться в конце каждой итерации цикла. Это происходит до следующего вычисления
condition. Обычно используется для обновления или инкремента переменной-счетчика. -
statement - Инструкция, которая выполняется до тех пор, пока условие вычисляется как true. Вы можете использовать инструкцию-блок для выполнения нескольких инструкций. Чтобы не выполнять никаких инструкций в цикле, используйте пустую инструкцию (
;).
Описание
Как и в других циклических инструкциях, вы можете использовать инструкции управления потоком внутри statement:
-
breakостанавливает выполнениеstatementи переходит к первой инструкции после цикла. -
continueостанавливает выполнениеstatementи повторно вычисляетafterthought, а затемcondition.
Примеры
Использование for
Следующая инструкция for начинается с объявления переменной i и инициализации ее значением 0. Она проверяет, что i меньше девяти, выполняет две последующие инструкции и увеличивает i на 1 после каждого прохода цикла.
for (let i = 0; i < 9; i++) {
console.log(i);
// more statements
}
Синтаксис блока инициализации
Блок инициализации принимает как выражения, так и объявления переменных. Однако выражения не могут использовать оператор in без скобок, так как это неоднозначно с циклом for...in.
for (let i = "start" in window ? window.start : 0; i < 9; i++) {
console.log(i);
}
// SyntaxError: 'for-in' loop variable declaration may not have an initializer.
// Parenthesize the whole initializer
for (let i = ("start" in window ? window.start : 0); i < 9; i++) {
console.log(i);
}
// Parenthesize the `in` expression
for (let i = ("start" in window) ? window.start : 0; i < 9; i++) {
console.log(i);
}
Необязательные выражения for
Все три выражения в заголовке цикла for необязательны. Например, не требуется использовать блок initialization для инициализации переменных:
let i = 0;
for (; i < 9; i++) {
console.log(i);
// more statements
}
Как и блок initialization, часть condition также необязательна. Если вы опускаете это выражение, вы должны убедиться, что прерываетесь в теле цикла, чтобы не создать бесконечный цикл.
for (let i = 0; ; i++) {
console.log(i);
if (i > 3) break;
// more statements
}
Вы также можете опустить все три выражения. Опять же, обязательно используйте инструкцию break для завершения цикла, а также изменяйте (увеличивайте) переменную, чтобы условие для инструкции break в какой-то момент стало истинным.
let i = 0;
for (;;) {
if (i > 3) break;
console.log(i);
i++;
}
Однако в случае, если вы не используете полностью все три позиции выражений — особенно если вы не объявляете переменные с первым выражением, а мутируете что-то во внешней области видимости — рассмотрите возможность использования вместо этого цикла while, который делает намерение более ясным.
let i = 0;
while (i <= 3) {
console.log(i);
i++;
}
Лексические объявления в блоке инициализации
Объявление переменной в блоке инициализации имеет важные отличия от объявления ее во внешней области видимости, особенно при создании замыкания в теле цикла. Например, для следующего кода:
for (let i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
Он выводит 0, 1 и 2, как и ожидалось. Однако, если переменная определена во внешней области видимости:
let i = 0;
for (; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
Он выводит 3, 3 и 3. Причина в том, что каждый setTimeout создает новое замыкание, которое захватывает переменную i, но если i не имеет области видимости тела цикла, все замыкания будут ссылаться на одну и ту же переменную, когда они в конечном итоге будут вызваны — и из-за асинхронной природы setTimeout(), это произойдет после того, как цикл уже завершится, что приведет к тому, что значение i во всех теле поставленных в очередь колбэков будет иметь значение 3.
Это также происходит, если вы используете инструкцию var в качестве инициализации, потому что переменные, объявленные с помощью var, имеют область видимости только на уровне функции, а не лексическую область видимости (то есть они не могут иметь область видимости тела цикла).
for (var i = 0; i < 3; i++) {
setTimeout(() => {
console.log(i);
}, 1000);
}
// Logs 3, 3, 3
Эффект области видимости блока инициализации можно рассматривать так, как если бы объявление происходило внутри тела цикла, но случайно было бы доступно в частях condition и afterthought. Точнее, объявления let имеют специальную обработку в циклах for — если initialization является объявлением let, то каждый раз, после вычисления тела цикла, происходит следующее:
- Создается новая лексическая область видимости с новыми переменными, объявленными с помощью
let. - Значения привязок из последней итерации используются для повторной инициализации новых переменных.
-
afterthoughtвычисляется в новой области видимости.
Таким образом, переприсвоение новых переменных в afterthought не влияет на привязки из предыдущей итерации.
Новая лексическая область видимости также создается после initialization, непосредственно перед первым вычислением condition. Эти детали можно наблюдать, создавая замыкания, которые позволяют вам получить привязку в любой конкретный момент. Например, в этом коде замыкание, созданное в разделе initialization, не обновляется при повторном присвоении i в afterthought:
for (let i = 0, getI = () => i; i < 3; i++) {
console.log(getI());
}
// Logs 0, 0, 0
Это не выводит "0, 1, 2", как это произошло бы, если бы getI была объявлена в теле цикла. Это потому, что getI не вычисляется на каждой итерации — скорее, функция создается один раз и замыкает переменную i, которая ссылается на переменную, объявленную при первоначальной инициализации цикла. Последующие обновления значения i фактически создают новые переменные с именем i, которые getI не видит. Способ исправить это — пересчитывать getI каждый раз, когда i обновляется:
for (let i = 0, getI = () => i; i < 3; i++, getI = () => i) {
console.log(getI());
}
// Logs 0, 1, 2
Переменная i внутри initialization отличается от переменной i внутри каждой итерации, включая первую. Итак, в этом примере getI возвращает 0, хотя значение i внутри итерации инкрементируется заранее:
for (let i = 0, getI = () => i; i < 3;) {
i++;
console.log(getI());
}
// Logs 0, 0, 0
На самом деле, вы можете захватить эту начальную привязку переменной i и переприсвоить ее позже, и это обновленное значение не будет видно телу цикла, которое видит следующую новую привязку i.
for (
let i = 0, getI = () => i, incrementI = () => i++;
getI() < 3;
incrementI()
) {
console.log(i);
}
// Logs 0, 0, 0
Это выводит "0, 0, 0", потому что переменная i в каждой оценке цикла на самом деле является отдельной переменной, но getI и incrementI читают и записывают *начальную* привязку i, а не то, что было объявлено впоследствии.
Использование for без тела
Следующий цикл for вычисляет смещенное положение узла в секции afterthought, и поэтому не требует использования секции statement, вместо этого используется точка с запятой.
function showOffsetPos(id) {
let left = 0;
let top = 0;
for (
let itNode = document.getElementById(id); // initialization
itNode; // condition
left += itNode.offsetLeft,
top += itNode.offsetTop,
itNode = itNode.offsetParent // afterthought
); // semicolon
console.log(
`Offset position of "${id}" element:
left: ${left}px;
top: ${top}px;`,
);
}
showOffsetPos("content");
// Logs:
// Offset position of "content" element:
// left: 0px;
// top: 153px;
Обратите внимание, что точка с запятой после инструкции for обязательна, поскольку она является пустой инструкцией. В противном случае инструкция for приобретает следующую строку console.log как свою секцию statement, что приводит к многократному выполнению log.
Использование for с двумя переменными итерации
Вы можете создать два счетчика, которые обновляются одновременно в цикле for, используя оператор запятая. Несколько объявлений let и var также могут быть объединены запятыми.
const arr = [1, 2, 3, 4, 5, 6];
for (let l = 0, r = arr.length - 1; l < r; l++, r--) {
console.log(arr[l], arr[r]);
}
// 1 6
// 2 5
// 3 4
Спецификации
Совместимость с браузерами
| Настольные компьютеры | Мобильные устройства | Сервер | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Chrome | Edge | Firefox | Opera | Safari | Chrome Android | Firefox for Android | Opera Android | Safari on iOS | Samsung Internet | WebView Android | WebView on iOS | Bun | Deno | Node.js | |
for |
1 |
12 |
1 |
3 |
1 |
18 |
4 |
10.1 |
1 |
1.0 |
4.4 |
1 |
1.0.0 |
1.0 |
0.10.0 |
См. также
© 2005–2025 MDN contributors.
Licensed under the Creative Commons Attribution-ShareAlike License v2.5 or later.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for