← Назад к вопросам

В чем разница между Listener и Observer?

2.3 Middle🔥 211 комментариев
#JavaScript Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

В чем разница между Listener и Observer

Listener и Observer часто путают, но это разные паттерны с разными целями, хотя оба используются для реактивного программирования и обработки событий.

Observer Pattern (Проектный паттерн)

Observer — это паттерн проектирования для связи между объектами с отношением один-ко-многим.

// Observer Pattern
class Subject {
  constructor() {
    this.observers = []; // Список наблюдателей
  }
  
  attach(observer) {
    this.observers.push(observer);
  }
  
  detach(observer) {
    this.observers = this.observers.filter(obs => obs !== observer);
  }
  
  notify(data) {
    // Уведомляем ВСЕ observers об изменении
    this.observers.forEach(observer => observer.update(data));
  }
}

// Конкретный observer
class Observer {
  update(data) {
    console.log("Observer уведомлен:", data);
  }
}

// Использование
const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();

subject.attach(observer1);
subject.attach(observer2);

subject.notify({ message: "Что-то изменилось" });
// Оба observer получат обновление

Характеристики Observer:

  • Один Subject (издатель) уведомляет множество Observers (подписчиков)
  • Observers знают о Subject и регистрируют себя (attach/detach)
  • Subject не знает о конкретных Observers, только что они есть
  • Связь слабая, но Observers должны реализовать интерфейс update()

Listener Pattern (Слушатель событий)

Listener — это функция или объект, которые "слушают" конкретное событие и реагируют на него.

// Listener Pattern
const button = document.querySelector("button");

// Listener — это просто функция
const clickListener = (event) => {
  console.log("Кнопка нажата", event);
};

// Регистрируем listener
button.addEventListener("click", clickListener);

// Удаляем listener
button.removeEventListener("click", clickListener);

Характеристики Listener:

  • Listener слушает конкретное событие (click, load, change, etc)
  • Listener регистрируется на объект, который генерирует события (EventTarget)
  • Может быть несколько listeners для одного события
  • Listener — это просто функция или метод

Основные отличия

ПараметрObserverListener
ТипПроектный паттернФункция обработки события
ЦельСинхронизация состояния между объектамиРеакция на конкретное событие
ПривязкаК объекту SubjectК конкретному событию
УведомлениеЧерез метод update()Через колбэк функцию
ЗнаниеObservers знают о SubjectListener не обязан знать об источнике
ИнтерфейсДолжен реализовать интерфейсПросто функция
В Web APIEventListenerНет встроенной реализации

Практический пример: Observer

// Реальный пример: Model-View Observer паттерн

class DataModel {
  constructor(data) {
    this.data = data;
    this.observers = [];
  }
  
  subscribe(observer) {
    this.observers.push(observer);
  }
  
  unsubscribe(observer) {
    this.observers = this.observers.filter(obs => obs !== observer);
  }
  
  update(newData) {
    this.data = newData;
    // Уведомляем всех observers
    this.notifyAll();
  }
  
  notifyAll() {
    this.observers.forEach(observer => observer.onDataChange(this.data));
  }
}

class View {
  constructor(name) {
    this.name = name;
  }
  
  onDataChange(newData) {
    console.log(`${this.name} обновлена:`, newData);
  }
}

// Использование
const model = new DataModel({ count: 0 });
const view1 = new View("View 1");
const view2 = new View("View 2");

model.subscribe(view1);
model.subscribe(view2);

model.update({ count: 1 });
// View 1 обновлена: { count: 1 }
// View 2 обновлена: { count: 1 }

Практический пример: Listener

// Listener в контексте DOM событий

class Form {
  constructor() {
    this.input = document.querySelector("input");
    this.button = document.querySelector("button");
    this.result = document.querySelector("#result");
  }
  
  init() {
    // Слушаем событие input
    this.input.addEventListener("input", this.handleInput.bind(this));
    
    // Слушаем событие click
    this.button.addEventListener("click", this.handleClick.bind(this));
  }
  
  handleInput(event) {
    // Listener реагирует на конкретное событие
    console.log("Input изменился:", event.target.value);
  }
  
  handleClick(event) {
    // Listener реагирует на конкретное событие
    console.log("Кнопка нажата");
  }
}

const form = new Form();
form.init();

В контексте React и современного JavaScript

Observer Pattern в React (RxJS)

import { BehaviorSubject } from "rxjs";

// Subject (как Observable)
const userSubject = new BehaviorSubject({ name: "John" });

// Observer 1
const observer1 = {
  next: (user) => console.log("Observer 1:", user),
  error: (err) => console.error("Error:", err),
  complete: () => console.log("Observer 1 completed")
};

// Observer 2
const observer2 = {
  next: (user) => console.log("Observer 2:", user)
};

// Подписываем observers
userSubject.subscribe(observer1);
userSubject.subscribe(observer2);

// Уведомляем всех
userSubject.next({ name: "Jane" });
// Observer 1: { name: "Jane" }
// Observer 2: { name: "Jane" }

Listener в React

function Button() {
  const handleClick = (event) => {
    console.log("Button clicked", event);
  };
  
  // Listener — это просто функция обработки события
  return <button onClick={handleClick}>Click me</button>;
}

Event Emitter паттерн (гибрид Observer + Listener)

// Node.js EventEmitter — гибрид両паттернов

const EventEmitter = require("events");

const emitter = new EventEmitter();

// Listener 1 слушает событие "message"
emitter.on("message", (data) => {
  console.log("Listener 1:", data);
});

// Listener 2 слушает то же событие
emitter.on("message", (data) => {
  console.log("Listener 2:", data);
});

// Эмитируем событие
emitter.emit("message", "Hello");
// Listener 1: Hello
// Listener 2: Hello

Когда что использовать

Observer Pattern:

  • Нужна синхронизация состояния между компонентами
  • Model-View-Controller архитектура
  • Нужна слабая связанность между объектами
  • Сложная логика уведомления

Listener Pattern:

  • Реакция на DOM события (click, input, load, etc)
  • Обработка пользовательских действий
  • Простая связь событие -> обработчик
  • Встроенная поддержка в DOM API

Сравнение в коде

// Observer: Модель уведомляет наблюдателей об ИЗМЕНЕНИИ СОСТОЯНИЯ
const dataModel = new DataModel();
const view1 = new View();
const view2 = new View();

dataModel.subscribe(view1);
dataModel.subscribe(view2);

dataModel.data = newValue; // Все views уведомлены об изменении

// Listener: Объект реагирует на КОНКРЕТНОЕ СОБЫТИЕ
const button = document.querySelector("button");
button.addEventListener("click", () => console.log("Clicked"));
button.addEventListener("mouseover", () => console.log("Hovered"));

// User clicks button: "Clicked" выведется
// User hovers button: "Hovered" выведется

Заключение

Observer — это архитектурный паттерн для синхронизации состояния между объектами. Один издатель (Subject) уведомляет множество подписчиков (Observers).

Listener — это просто функция, которая реагирует на конкретное событие. Слушает события, не обязательно управляя состоянием.

Простое объяснение:

  • Observer: "У меня произошла важная вещь (изменение состояния), все мои наблюдатели должны это знать"
  • Listener: "Я слушаю, когда произойдёт ЭТО КОНКРЕТНОЕ событие (click, change, etc), и как на него реагировать"

В современном JavaScript Observer часто реализуется через Observables (RxJS) или Proxies, а Listener — через addEventListener() в DOM.

В чем разница между Listener и Observer? | PrepBro