Какая разница между методом экземпляра и статическим методом?
В данный момент занимаюсь изучением классов и интересует такой вот вопрос. Подскажите пожалуйста, какая разница между методом экземпляра и статическим методом в классе Javascript? Синтаксис этих методов мне известен, как вызвать и как применить тоже знаю. Вопрос в том, в каких случаях и какой вид метода лучше применять? Статьи про классы не дают внятного объяснения о разнице между этими методами, кроме как о их правильности написания в коде.
Ответы (1 шт):
Статические члены класса всего лишь удобный способ объявить некоторый функционал и/или некоторое состояние в именованном пространстве имен.
К примеру метод 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>