Лучшие практики итерации в JavaScript

Лучшие практики итерации в 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-канал.

YouTube Video