Эмуляция static переменной в JavaScript (как в PHP)

Статические переменные – мощный инструмент в языках программирования, таких как PHP. Ключевое слово static делает переменную внутри функции постоянной, то есть она не удаляется после окончания работы функции. Это означает, что вы можете сохранить значения между вызовами функции, "заморозив" переменную.

В JavaScript нет аналогичного понятия статической переменной. Однако можно добиться похожего поведения с помощью замыканий.

Создание статической переменной через замыкание в JavaScript

В JavaScript функция, внутри которой определена другая функция, формирует замыкание. Внутренняя функция имеет доступ к переменным внешней функции, даже после того, как выполнение внешней функции завершено. Это дает нам возможность эмулировать статические переменные.

function MyFunction() {
  let counter = 0;

  return function() {
	counter += 1;
	return counter;
  }
}

let instance = MyFunction();

console.log( instance() ); // выводит 1
console.log( instance() ); // выводит 2
console.log( instance() ); // выводит 3

В этом примере: MyFunction возвращает новую функцию, которая увеличивает значение счетчика на 1 при каждом вызове. Это значение "заморожено" и существует между вызовами благодаря замыканию.

Однако, если вы вызываете MyFunction снова, вы получите новый, отдельный счетчик. Это отличает этот подход от статических переменных в PHP, которые были бы общие для всех вызовов функции.

console.log( MyFunction()() ); // выводит 1
console.log( MyFunction()() ); // выводит 1
console.log( MyFunction()() ); // выводит 1

Если вам нужна общая статическая переменная в JavaScript, вам придется использовать глобальные переменные или свойства объектов для сохранения значений.

Еще пример

Перепишем следующий код, чтобы не сломать его логики, но при этом поместить staticVar внутрь функции myFunction():

let staticVar = false;
export function myFunction() {

	if( ! staticVar ) {
		staticVar = new MyObject()
	}

	return staticVar
}

Тут можно использовать паттерн модуля и захватить staticVar внутри замыкания, чтобы сделать его приватным:

export const myFunction = ( function() {
  let staticVar = null;

  return function() {
	if ( ! staticVar ) {
	  staticVar = new MyObject();
	}

	return staticVar;
  }
} )();

Теперь staticVar является "статической" переменной, значение которой сохраняется между вызовами myFunction(), но не выглядит как глобальная переменная, так как она находится внутри области видимости самовызывающейся функции.