Статические переменные в JavaScript: глобальный доступ и сохранение

Пройдите тест, узнайте какой профессии подходите

Я предпочитаю
0%
Работать самостоятельно и не зависеть от других
Работать в команде и рассчитывать на помощь коллег
Организовывать и контролировать процесс работы

Быстрый ответ

Для работы со статическими переменными в JavaScript часто используют замыкания или присваивают свойства функциям-конструкторам. Пример с применением замыкания:

JS
Скопировать код
function createCounter() {
  let count = 0;
  return () => count++;
}

const counter = createCounter();
console.log(counter()); // Вывод: 0
console.log(counter()); // Вывод: 1

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

Кинга Идем в IT: пошаговый план для смены профессии

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

Классы ES6 предоставляют функциональность для создания статических переменных с помощью ключевого слова static. Такие переменные привязываются к самому классу, а не к его экземплярам.

JS
Скопировать код
class MyClass {
  static myStaticValue = 0;
  
  static increment() {
    this.myStaticValue++;
  }
}

MyClass.increment();
console.log(MyClass.myStaticValue); // Вывод: 1

Следовательно, статическая переменная будет общей для всех экземпляров класса.

Защита статических переменных посредством замыканий

Замыкания дают возможность создавать приватные статические переменные, которые не доступны непосредственно извне, но можно изменять их через предоставленные методы.

JS
Скопировать код
let Library = (function () {
  let bookCount = 0;
  return class {
    static incrementBooks() {
      return ++bookCount;
    }
  }
})();

console.log(Library.incrementBooks()); // Вывод: 1

Такая конструкция помогает защитить bookCount от прямого доступа извне – изменения возможны только с помощью метода incrementBooks.

Общие методы с помощью prototype

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

JS
Скопировать код
function Animal() {}
Animal.prototype.speak = function () {
  return 'Это животное издает звук.';
};

let dog = new Animal();
console.log(dog.speak()); // Вывод: Это животное издает звук.

Все экземпляры Animal используют одну и ту же функцию speak, которая занимает место в памяти только в единственном экземпляре.

Управление доступом с использованием Object.defineProperty

Для точного контроля над доступом к переменным можно использовать Object.defineProperty для создания геттеров и сеттеров.

JS
Скопировать код
class Example {
  static #secretValue = 123;

  static get secretValue() {
    return Example.#secretValue;
  }

  static set secretValue(val) {
    Example.#secretValue = val;
  }
}

console.log(Example.secretValue); // Вывод: 123
Example.secretValue = 456;
console.log(Example.secretValue); // Вывод: 456

Визуализация

Давайте представим общественный парк в качестве места общего пользования:

Markdown
Скопировать код
Парк (🌳): [Посетитель1, Посетитель2, Посетитель3]

А теперь давайте представим статическую переменную в роли скамейки в этом парке:

JS
Скопировать код
function ParkBench() {
  if (typeof ParkBench.counter == 'undefined') {
    ParkBench.counter = 0;
  }
  ParkBench.counter++;
}

Каждый новый визит в парк увеличивает количество людей, отдохнувших на одной и той же скамейке:

Markdown
Скопировать код
Статическая скамья (🪑): [Посетитель1 (1), Посетитель2 (2), Посетитель3 (3)]

Таким образом, статическая переменная отслеживает посещаемость скамейки, даже если посетители посещают парк не одновременно.

На помощь приходят модули!

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

JS
Скопировать код
var MyApp = (function() {
  var privateStaticVar = 0;

  return {
    increment: function() {
      return ++privateStaticVar;
    },
    value: function() {
      return privateStaticVar;
    }
  };
})();

console.log(MyApp.increment()); // Вывод: 1
console.log(MyApp.value()); // Вывод: 1

Внедрение TypeScript

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

typescript
Скопировать код
class MyClass {
  private static count = 0;

  public static increment() {
    this.count++;
  }
}

MyClass.increment();
// console.log(MyClass.count); // Ошибка: 'count' – приватная переменная, доступная только в MyClass.

Работа со статическими переменными в анонимных функциях

В анонимной функции можно поддерживать статическую переменную с помощью arguments.callee.

JS
Скопировать код
let anonymousCounter = (function() {
  let count = 0;
  return function() {
    count++;
    console.log(count, arguments.callee);
  };
})();

anonymousCounter(); // Вывод: 1, [Function]

Полезные материалы

  1. static – JavaScript | MDN — руководство по статическим свойствам классов на MDN.
  2. Область видимости переменных, замыкание — подробное объяснение замыканий в JavaScript.
  3. Основы модульного паттерна JavaScript — статья, рассказывающая о создании модулей.
  4. Паттерны проектирования JavaScript: Singleton — о использовании синглтон-паттерна для управления состоянием.
  5. Классы в JavaScript — анализ различий между статическими и инстансными свойствами классов.
  6. Understanding ECMAScript 6 — детальный анализ классов ES6 и статических свойств.
  7. Статические переменные в JavaScript – Stack Overflow — обсуждение статических переменных в сообществе Stack Overflow.