Лучшие практики итерации в JavaScript
Эта статья объясняет лучшие практики итерации в JavaScript.
YouTube Video
Лучшие практики итерации в JavaScript
В JavaScript обычно используют циклы for для итерации. Здесь мы дадим подробное объяснение лучших практик использования циклов for для написания эффективного и читаемого кода.
Выберите правильную структуру цикла
JavaScript предлагает несколько конструкций циклов, каждая из которых подходит для разных целей.
1// Example of a for loop
2for (let i = 0; i < 5; i++) {
3 console.log(i);
4}
5
6// Example of a for...of loop
7const array = [10, 20, 30];
8for (const value of array) {
9 console.log(value);
10}
11
12// Example of a for...in loop
13const obj = { a: 1, b: 2, c: 3 };
14for (const key in obj) {
15 console.log(`${key}: ${obj[key]}`);
16}
17
18// Example of a while loop
19let count = 0;
20while (count < 5) {
21 console.log(count);
22 count++;
23}- Оператор
forподходит, когда количество итераций заранее определено. - Оператор
for...ofподходит для лаконичной обработки массивов и итерируемых объектов. - Оператор
for...inиспользуется для перебора свойств объекта. Однако он не подходит для работы с массивами. - Операторы
whileиdo...whileиспользуются для управления циклами на основе условий.
Использование метода forEach и оператора for...of
При переборе массива использование оператора for для доступа к индексу является стандартным, но метод forEach или оператор for...of могут быть более читаемыми.
1// Using a standard for loop
2const array = ["apple", "banana", "cherry"];
3for (let i = 0; i < array.length; i++) {
4 console.log(array[i]);
5}
6
7// Using forEach
8array.forEach(item => console.log(item));
9
10// Using for...of
11for (const item of array) {
12 console.log(item);
13}- Оператор
forпозволяет явно управлять индексом во время итерации. - Метод
forEachиспользует функцию обратного вызова для лаконичной обработки каждого элемента. - Оператор
for...ofобладает высокой читаемостью и позволяет напрямую получать доступ к каждому элементу массива.
Оптимизируйте условия цикла
Поскольку условие цикла оценивается многократно, избегание ненужных вычислений может улучшить производительность.
1const names = ["Alice", "Bob", "Charlie"];
2const scores = [85, 92, 78];
3
4// Inefficient example
5for (let i = 0; i < Math.min(names.length, scores.length); i++) {
6 console.log(`${names[i]} scored ${scores[i]}`);
7}
8
9// Efficient example
10for (let i = 0, len = Math.min(names.length, scores.length); i < len; i++) {
11 console.log(`${names[i]} scored ${scores[i]}`);
12}- Как показано в этом примере, сохранение результата вычислений в переменной заранее позволяет выполнить цикл более эффективно.
1const scores = [85, 92, 78];
2let sum = 0;
3let sum2 = 0;
4
5// Inefficient example
6for (let i = 0; i < scores.length; i++) {
7 sum += scores[i];
8}
9console.log(`Total score : ${sum}`);
10
11// Efficient example
12for (let i = scores.length - 1; i >= 0; i--) {
13 sum2 += scores[i];
14}
15console.log(`Total score : ${sum2}`);- Как показано в этом примере, изменение условия на противоположное может быть более эффективным.
Оптимизация обработки циклов
Так как обработка циклов выполняется многократно, избегание лишних вычислений может улучшить производительность.
1const array = ["apple", "banana", "cherry"];
2
3// Inefficient example
4for (let i = 0; i < 100; i++) {
5 const element = document.querySelector("#myElement");
6 element.textContent = `Count: ${i}`;
7}
8
9// Efficient example
10const element = document.querySelector("#myElement");
11for (let i = 0; i < 100; i++) {
12 element.textContent = `Count: ${i}`;
13}- В этом примере перемещение метода
querySelectorза пределы цикла устраняет ненужные повторные вычисления.
Учитывайте область видимости
Используйте let или const, чтобы переменные внутри цикла имели правильную область видимости. Поскольку var ограничен областью видимости функции, он может привести к неожиданному поведению.
1// Using let
2for (let i = 0; i < 3; i++) {
3 console.log(i);
4}
5
6// Potential issue with var
7for (var i = 0; i < 3; i++) {
8 setTimeout(() => console.log(i), 1000); // 3, 3, 3
9}
10
11// Using let to avoid the issue
12for (let i = 0; i < 3; i++) {
13 setTimeout(() => console.log(i), 1000); // 0, 1, 2
14}varимеет функциональную область видимости, поэтому после завершения цикла значениеiостается3, и все функции, выполняемые черезsetTimeout, выводят3.- При использовании
letзначениеiвнутри функции обратного вызоваsetTimeoutявляется новым для каждой итерации, поэтому выводятся0, 1, 2, как и ожидалось.
Улучшите читабельность с помощью ранних выходов
Чтобы упростить обработку циклов, используйте break и continue таким образом, чтобы улучшить читаемость.
1// Example using break
2for (let i = 0; i < 10; i++) {
3 if (i === 5) {
4 break; // Exit the loop
5 }
6 console.log(i);
7}
8
9// Example using continue
10for (let i = 0; i < 10; i++) {
11 if (i % 2 === 0) {
12 continue; // Skip to the next iteration
13 }
14 console.log(i);
15}- Использование
breakпозволяет завершить выполнение цикла досрочно, пропустив все последующие итерации. - Использование
continueпозволяет пропустить текущую итерацию цикла и перейти к следующей.
Избегайте глубокого вложения
Глубокое вложение ухудшает читаемость кода, поэтому старайтесь уменьшать уровень вложенности, используя ранние возвращения или разделение функциональности на функции.
1// Deeply nested example
2for (let i = 0; i < 5; i++) {
3 for (let j = 0; j < 5; j++) {
4 if (i + j > 5) {
5 console.log(i, j);
6 }
7 }
8}
9
10// Improved using function decomposition
11function processPairs(i) {
12 for (let j = 0; j < 5; j++) {
13 if (i + j > 5) {
14 console.log(i, j);
15 }
16 }
17}
18
19for (let i = 0; i < 5; i++) {
20 processPairs(i);
21}- В этом примере используются функции для уменьшения уровня вложенности.
Рассмотрение обработки ошибок
Если существует вероятность возникновения ошибок в цикле, реализуйте корректную обработку ошибок.
1const data = ["123", "abc", "456", "xyz"];
2
3// Without Error Handling
4for (const item of data) {
5 const result = parseInt(item);
6 console.log(`Parsed value: ${result}`);
7}
8
9// With Error Handling
10for (const item of data) {
11 try {
12 const result = parseInt(item);
13 if (isNaN(result)) {
14 throw new Error(`Invalid number: ${item}`);
15 }
16 console.log(`Parsed value: ${result}`);
17 } catch (error) {
18 console.error(`Error processing item: ${item}. ${error.message}`);
19 }
20}- В этом примере реализована обработка ошибок для обработки некорректных данных, обнаружения и сообщения о проблемах.
Моменты, на которые следует обратить внимание при асинхронной обработке
При обработке асинхронных операций в циклах использование async/await может привести к лаконичному и интуитивно понятному коду.
1const urls = ["https://example.com/1", "https://example.com/2"];
2
3// Proper handling of asynchronous operations
4async function fetchUrls() {
5 for (const url of urls) {
6 const response = await fetch(url);
7 const data = await response.json();
8 console.log(data);
9 }
10}
11
12fetchUrls();- Этот код асинхронно извлекает URL-адреса из массива
urlsпо одному и обрабатывает результаты в формате JSON. Использованиеasync/awaitупрощает асинхронные операции, последовательно извлекая данные для каждого URL и выводя их в консоль.
Поймите разницу между оператором for...of и методом forEach() при асинхронной обработке.
1async function asyncTask(num) {
2 return new Promise(resolve => {
3 setTimeout(() => {
4 console.log(`Task ${num} done`);
5 resolve();
6 }, 100);
7 });
8}
9
10async function runWithForOf() {
11 console.log("Start for...of");
12 for (const num of [1, 2, 3]) {
13 await asyncTask(num);
14 }
15 console.log("End for...of");
16}
17
18async function runWithForEach() {
19 console.log("Start forEach");
20 [1, 2, 3].forEach(async num => {
21 await asyncTask(num);
22 });
23 console.log("End forEach");
24}
25
26async function executeExamples() {
27 await runWithForOf();
28 await runWithForEach();
29}
30
31executeExamples();-
При обработке асинхронных операций в циклах обратите внимание на различия в поведении, как показано в этом примере, между использованием
for...ofсasync/awaitи использованиемforEach(). -
При использовании
for...ofкод выполняется последовательно и останавливается наawaitвнутри цикла, прежде чем перейти к следующей итерации. С другой стороны,forEach()выполняет обработку параллельно.
Заключение
Оператор for в JavaScript — это простой, но мощный инструмент. Используя представленные здесь наилучшие практики, вы сможете писать эффективный и легко читаемый код. Обратите внимание на выбор подходящей конструкции цикла, управление областью видимости, обработку ошибок и стремитесь к созданию легко поддерживаемого кода.
Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.