Home » Метод filter массива в JavaScript — как использовать
Метод filter массива в JavaScript — как использовать

Метод filter массива в JavaScript — как использовать

Массивы в JavaScript — это хлеб и масло для любого разработчика, а метод filter() без преувеличения можно назвать одним из самых мощных инструментов для работы с данными. Если вы настраиваете серверы, пишете скрипты для автоматизации или парсите логи, то этот метод станет вашим верным спутником в решении множества задач.

Думаю, многие из вас сталкивались с ситуацией, когда нужно отфильтровать массив процессов в системе, выбрать только нужные строки из конфигурационного файла или обработать JSON-ответ от API. Именно в таких случаях filter() показывает свою силу — он позволяет создавать новые массивы на основе определённых условий, не мутируя исходные данные.

Сегодня разберём, как правильно использовать этот метод, рассмотрим практические примеры из повседневной работы с серверами и автоматизацией, а также покажем, как интегрировать его в ваши Node.js скрипты для мониторинга и управления инфраструктурой.

Как работает метод filter()

Метод filter() создаёт новый массив, содержащий только те элементы исходного массива, которые проходят проверку, реализованную в переданной функции. Проще говоря, вы задаёте условие, а метод возвращает только подходящие элементы.

Синтаксис выглядит следующим образом:

array.filter(callback(element, index, array), thisArg)

Где:

  • callback — функция, которая проверяет каждый элемент
  • element — текущий элемент массива
  • index — индекс текущего элемента (необязательный)
  • array — исходный массив (необязательный)
  • thisArg — значение this для функции callback (необязательный)

Важно помнить, что filter() не изменяет исходный массив, а создаёт новый. Это делает его безопасным для использования в функциональном программировании.

Пошаговая настройка и базовые примеры

Давайте начнём с простых примеров, которые помогут понять основы работы с методом:

// Пример 1: Фильтрация чисел
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const evenNumbers = numbers.filter(num => num % 2 === 0);
console.log(evenNumbers); // [2, 4, 6, 8, 10]

// Пример 2: Фильтрация строк
const processes = ['nginx', 'apache2', 'mysql', 'redis', 'postgres'];
const webServers = processes.filter(process => process.includes('nginx') || process.includes('apache'));
console.log(webServers); // ['nginx', 'apache2']

// Пример 3: Фильтрация объектов
const servers = [
  { name: 'web-01', cpu: 85, memory: 70, status: 'active' },
  { name: 'web-02', cpu: 45, memory: 60, status: 'active' },
  { name: 'db-01', cpu: 90, memory: 85, status: 'warning' },
  { name: 'cache-01', cpu: 25, memory: 40, status: 'active' }
];

const overloadedServers = servers.filter(server => server.cpu > 80 || server.memory > 80);
console.log(overloadedServers);
// [{ name: 'web-01', cpu: 85, memory: 70, status: 'active' }, 
//  { name: 'db-01', cpu: 90, memory: 85, status: 'warning' }]

Практические примеры для системного администрирования

Теперь рассмотрим реальные сценарии, с которыми сталкивается каждый, кто работает с серверами:

Анализ логов веб-сервера

const fs = require('fs');
const path = require('path');

// Парсим access.log и фильтруем ошибки
function parseAccessLog(logPath) {
  const logData = fs.readFileSync(logPath, 'utf8').split('\n');
  
  const errorEntries = logData
    .filter(line => line.includes(' 4') || line.includes(' 5')) // HTTP 4xx, 5xx
    .filter(line => line.trim() !== '') // Удаляем пустые строки
    .map(line => {
      const parts = line.split(' ');
      return {
        ip: parts[0],
        timestamp: parts[3] + ' ' + parts[4],
        method: parts[5],
        url: parts[6],
        status: parts[8],
        size: parts[9]
      };
    });
  
  return errorEntries;
}

// Использование
const errors = parseAccessLog('/var/log/nginx/access.log');
console.log(`Найдено ${errors.length} ошибок`);

Мониторинг процессов системы

const { exec } = require('child_process');

function getHighCPUProcesses(threshold = 80) {
  return new Promise((resolve, reject) => {
    exec('ps aux --sort=-%cpu', (error, stdout) => {
      if (error) {
        reject(error);
        return;
      }
      
      const processes = stdout.split('\n')
        .slice(1) // Убираем заголовок
        .filter(line => line.trim() !== '')
        .map(line => {
          const parts = line.trim().split(/\s+/);
          return {
            user: parts[0],
            pid: parts[1],
            cpu: parseFloat(parts[2]),
            memory: parseFloat(parts[3]),
            command: parts.slice(10).join(' ')
          };
        })
        .filter(process => process.cpu > threshold);
      
      resolve(processes);
    });
  });
}

// Использование
getHighCPUProcesses(50).then(processes => {
  console.log('Процессы с высокой нагрузкой на CPU:');
  processes.forEach(p => {
    console.log(`${p.command} (PID: ${p.pid}, CPU: ${p.cpu}%)`);
  });
});

Фильтрация конфигураций Docker контейнеров

const { exec } = require('child_process');

function getRunningContainers() {
  return new Promise((resolve, reject) => {
    exec('docker ps --format "{{.Names}},{{.Status}},{{.Ports}}"', (error, stdout) => {
      if (error) {
        reject(error);
        return;
      }
      
      const containers = stdout.trim().split('\n')
        .filter(line => line.trim() !== '')
        .map(line => {
          const [name, status, ports] = line.split(',');
          return { name, status, ports };
        })
        .filter(container => container.status.includes('Up')); // Только запущенные
      
      resolve(containers);
    });
  });
}

// Фильтрация по портам
function getWebContainers(containers) {
  return containers.filter(container => 
    container.ports.includes(':80->') || 
    container.ports.includes(':443->') ||
    container.ports.includes(':8080->')
  );
}

Продвинутые техники и комбинации

Настоящая мощь filter() раскрывается при его комбинации с другими методами массивов:

// Цепочка методов для обработки серверной статистики
const serverMetrics = [
  { server: 'web-01', timestamp: '2024-01-15T10:00:00Z', cpu: 85, memory: 70 },
  { server: 'web-01', timestamp: '2024-01-15T10:05:00Z', cpu: 90, memory: 75 },
  { server: 'web-02', timestamp: '2024-01-15T10:00:00Z', cpu: 45, memory: 60 },
  { server: 'web-02', timestamp: '2024-01-15T10:05:00Z', cpu: 50, memory: 65 },
  { server: 'db-01', timestamp: '2024-01-15T10:00:00Z', cpu: 95, memory: 85 }
];

// Находим критичные метрики и группируем по серверам
const criticalMetrics = serverMetrics
  .filter(metric => metric.cpu > 80 || metric.memory > 80)
  .map(metric => ({
    ...metric,
    severity: metric.cpu > 90 || metric.memory > 90 ? 'critical' : 'warning'
  }))
  .reduce((acc, metric) => {
    if (!acc[metric.server]) {
      acc[metric.server] = [];
    }
    acc[metric.server].push(metric);
    return acc;
  }, {});

console.log(criticalMetrics);

Сравнение с альтернативными подходами

Метод Производительность Читаемость Гибкость Подходит для
filter() Высокая Отличная Высокая Большинство задач
for loop Очень высокая Средняя Максимальная Критичные по производительности операции
forEach + push Средняя Низкая Средняя Не рекомендуется
reduce() Средняя Низкая Очень высокая Сложные трансформации

Интеграция с популярными библиотеками

Метод filter() отлично работает с библиотеками, которые часто используются в серверных приложениях:

Lodash

const _ = require('lodash');

// Комбинация filter с lodash утилитами
const servers = [
  { name: 'web-01', tags: ['production', 'frontend'], cpu: 85 },
  { name: 'web-02', tags: ['staging', 'frontend'], cpu: 45 },
  { name: 'db-01', tags: ['production', 'database'], cpu: 90 }
];

// Используем lodash для более сложных фильтров
const productionServers = servers.filter(server => 
  _.includes(server.tags, 'production') && server.cpu < 95
);

// Или используем встроенные методы lodash
const filteredServers = _.filter(servers, server => 
  _.some(server.tags, tag => tag.includes('prod'))
);

Moment.js для фильтрации по времени

const moment = require('moment');

const logs = [
  { message: 'Server started', timestamp: '2024-01-15T08:00:00Z' },
  { message: 'High CPU usage', timestamp: '2024-01-15T10:30:00Z' },
  { message: 'Database connection lost', timestamp: '2024-01-15T14:45:00Z' }
];

// Фильтруем логи за последние 6 часов
const recentLogs = logs.filter(log => 
  moment(log.timestamp).isAfter(moment().subtract(6, 'hours'))
);

Оптимизация и производительность

При работе с большими объёмами данных важно учитывать производительность:

// Неэффективно - множественные проходы
const data = getLargeDataSet();
const step1 = data.filter(item => item.type === 'server');
const step2 = step1.filter(item => item.status === 'active');
const step3 = step2.filter(item => item.cpu > 80);

// Эффективно - один проход
const optimized = data.filter(item => 
  item.type === 'server' && 
  item.status === 'active' && 
  item.cpu > 80
);

// Для очень больших массивов можно использовать индексы
const indexedData = new Map();
data.forEach((item, index) => {
  if (item.type === 'server') {
    indexedData.set(item.id, { ...item, originalIndex: index });
  }
});

Автоматизация и скрипты мониторинга

Создадим полноценный скрипт мониторинга, который можно запускать по cron:

#!/usr/bin/env node

const fs = require('fs');
const path = require('path');
const { exec } = require('child_process');

class ServerMonitor {
  constructor(config) {
    this.config = config;
    this.alerts = [];
  }

  async checkDiskSpace() {
    return new Promise((resolve, reject) => {
      exec("df -h | grep -E '^/dev/'", (error, stdout) => {
        if (error) {
          reject(error);
          return;
        }

        const disks = stdout.trim().split('\n')
          .map(line => {
            const parts = line.split(/\s+/);
            return {
              filesystem: parts[0],
              size: parts[1],
              used: parts[2],
              available: parts[3],
              usePercent: parseInt(parts[4].replace('%', '')),
              mountPoint: parts[5]
            };
          })
          .filter(disk => disk.usePercent > this.config.diskThreshold);

        resolve(disks);
      });
    });
  }

  async checkMemory() {
    return new Promise((resolve, reject) => {
      exec('free -m', (error, stdout) => {
        if (error) {
          reject(error);
          return;
        }

        const lines = stdout.trim().split('\n');
        const memoryLine = lines[1].split(/\s+/);
        const total = parseInt(memoryLine[1]);
        const available = parseInt(memoryLine[6]);
        const usedPercent = Math.round(((total - available) / total) * 100);

        resolve({
          total,
          available,
          usedPercent,
          alert: usedPercent > this.config.memoryThreshold
        });
      });
    });
  }

  async runMonitoring() {
    console.log('🔍 Запуск мониторинга сервера...');
    
    try {
      const [diskAlerts, memoryStatus] = await Promise.all([
        this.checkDiskSpace(),
        this.checkMemory()
      ]);

      // Фильтруем критичные диски
      const criticalDisks = diskAlerts.filter(disk => disk.usePercent > 90);
      
      if (criticalDisks.length > 0) {
        console.log('🚨 Критичное заполнение дисков:');
        criticalDisks.forEach(disk => {
          console.log(`  ${disk.mountPoint}: ${disk.usePercent}%`);
        });
      }

      if (memoryStatus.alert) {
        console.log(`🚨 Высокое использование памяти: ${memoryStatus.usedPercent}%`);
      }

      // Сохраняем результаты
      const results = {
        timestamp: new Date().toISOString(),
        diskAlerts,
        memoryStatus,
        criticalDisks
      };

      fs.writeFileSync('/tmp/server-monitor.json', JSON.stringify(results, null, 2));
      console.log('✅ Мониторинг завершён');

    } catch (error) {
      console.error('❌ Ошибка мониторинга:', error);
    }
  }
}

// Конфигурация
const config = {
  diskThreshold: 80,
  memoryThreshold: 85
};

// Запуск
const monitor = new ServerMonitor(config);
monitor.runMonitoring();

Интересные факты и нестандартные применения

Несколько интересных особенностей filter(), которые могут пригодиться:

  • Sparse arrays: filter() пропускает пустые элементы массива (holes), что делает его полезным для очистки разреженных массивов
  • Type coercion: Возвращаемое значение callback приводится к boolean, поэтому можно использовать краткие формы
  • Immutability: Идеально подходит для Redux и других state management решений
// Очистка разреженного массива
const sparse = [1, , 3, , 5];
const dense = sparse.filter(() => true); // [1, 3, 5]

// Фильтрация "truthy" значений
const mixed = [0, 1, false, 2, '', 3, null, 4, undefined, 5];
const truthy = mixed.filter(Boolean); // [1, 2, 3, 4, 5]

// Удаление дубликатов (в комбинации с indexOf)
const duplicates = [1, 2, 2, 3, 3, 3, 4];
const unique = duplicates.filter((item, index) => duplicates.indexOf(item) === index);

Развёртывание и тестирование

Для полноценной работы с серверными скриптами рекомендую использовать качественный VPS хостинг с достаточными ресурсами для Node.js приложений. Если планируете обрабатывать большие объёмы данных, стоит рассмотреть выделенный сервер для максимальной производительности.

Заключение и рекомендации

Метод filter() — это фундаментальный инструмент, который должен быть в арсенале каждого разработчика, работающего с серверными технологиями. Он отлично подходит для:

  • Анализа логов и мониторинга системы
  • Обработки конфигурационных файлов
  • Фильтрации данных в API
  • Создания скриптов автоматизации
  • Работы с метриками и статистикой

Ключевые принципы использования:

  • Всегда возвращайте boolean из callback функции
  • Помните, что filter() создаёт новый массив
  • Используйте цепочки методов для сложных операций
  • Оптимизируйте условия для больших массивов
  • Комбинируйте с другими методами массивов для максимальной эффективности

Освоив filter() и его интеграцию с серверными задачами, вы сможете создавать более элегантные и производительные решения для автоматизации и мониторинга инфраструктуры.


В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.

Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.

Leave a reply

Your email address will not be published. Required fields are marked