Какая разница между методом экземпляра и статическим методом?

В данный момент занимаюсь изучением классов и интересует такой вот вопрос. Подскажите пожалуйста, какая разница между методом экземпляра и статическим методом в классе Javascript? Синтаксис этих методов мне известен, как вызвать и как применить тоже знаю. Вопрос в том, в каких случаях и какой вид метода лучше применять? Статьи про классы не дают внятного объяснения о разнице между этими методами, кроме как о их правильности написания в коде.


Ответы (1 шт):

Автор решения: Alexander Lonberg

Статические члены класса всего лишь удобный способ объявить некоторый функционал и/или некоторое состояние в именованном пространстве имен.

К примеру метод parseInt есть и в window.parseInt(), но логичнее иметь его в пространство имен Number. Это, в том числе, позволяет проще ориентироваться в API, ведь когда мы ищем некоторую функцию и знаем что это касается числа, скорее всего справочник мы откроем на странице Number. Какой бы ожидал нас ужас, имея статические методы isArray(), isInteger(), ... десятков классов в глобальном объекте.

Статический метод не имеет привязки к this объекта, так как класс является шаблоном(и реализацией), а не реальным объектом. Соответственно статические члены не могут обратиться к полям и ничего сказать о состоянии реального объекта. Но реальная польза статических членов - взаимодействие с экземплярами всего класса.

К примеру мы создаем некоторый тип объектов, где только один может быть активен. Кроме того, мы не знаем о существовании объектов и задачей является использовать единственно доступный метод включения/выключения подсветки активного элемента. Можно создать статические поля и метод взаимодействия со всеми экземплярами класса, а объекты, в свою очередь, будут менять общее состояние всего класса.

// Этот класс предоставляет только один общедоступный статический метод взаимодействия со всеми экземплярами
class SomeClass {

  // Общее свойство/состояние для всех экземпляров в пространстве имен SomeClass
  // Мы используем приватные поля, чтобы пользователи не смогли наделать глупостей и сломать наш объект
  // Обращение к приватному статическому свойству SomeClass.#activeElement - вызовет ошибку Private field
  static #activeElement = { classList: { remove: (_) => null, add: (_) => null } }
  static #show = null

  constructor(el) {
    el.addEventListener('click', () => {
      // Здесь мы можем обратится к статическому свойству, только через SomeClass
      // т.к this привязан к конкретному экземпляру класса

      // Текущий экземпляр ничего не знает о своем родственном элементе, 
      // но знает что должен удалить подстветку старого элемента и подсветить себя.
      SomeClass.#activeElement.classList.remove('active')
      // Текущий элемент становится активным для всех экземпляров класса.
      SomeClass.#activeElement = el
      if (!SomeClass.#show) return
      SomeClass.#activeElement.classList.add('active')
    })
  }

  // Из этого общедоступного метода мы имеем доступ к текущему состоянию наших объектов
  static showActive(state) {
    // Здесь this имеет привязку к SomeClass.
    // По другому можно написать и так SomeClass.#show - ничего не изменится
    this.#show = state
    // Вариант доступа через SomeClass
    SomeClass.#activeElement.classList[state ? 'add' : 'remove']('active')
  }
}

// Нам даже не нужна ссылка на экземпляры класса - Просто создаем объекты.
document.querySelectorAll('div').forEach((d) => new SomeClass(d))

// Некоторый клиентский код может ничего не знать о существовании объектов и не знать когда они будут созданы,
// но использовать статический метод, когда пользователь желает отобразить подсветку активного элемента.
let h = false
document.querySelector('button').addEventListener('click',
  () => SomeClass.showActive(h = !h)
)
div {
  width: 60px;
  height: 60px;
  margin: 8px;
  float: left;
  text-align: center;
  line-height: 60px;
  font-size: 32px;
  background-color: #ffc107;
  cursor: pointer;
  user-select: none;
}

div.active {
  outline: 4px solid #e91e63;
}
<p>
  Кликни любой элемент и нажми подсветку. Независимо от состояния подсветки, последний "кликнутый" элемент будет всегда сохранен в статическом свойстве
</p>
<div>1</div>
<div>2</div>
<div>3</div>
<br>
<button>Покажи/спрячь активный div</button>

→ Ссылка