Можно ли скрыть только поля при инкапсуляции в JavaScript/Node.js?

Ответ

В чистом JavaScript (ES6 и выше) нет встроенных модификаторов доступа, таких как private, но есть несколько паттернов для эмуляции приватных полей.

1. Приватные поля класса (современный стандарт, ES2022): Самый чистый и рекомендуемый способ. Поле становится недоступным за пределами класса.

class User {
  #secretKey; // Приватное поле
  name;      // Публичное поле

  constructor(name, key) {
    this.name = name;
    this.#secretKey = key;
  }

  getKeyHash() {
    // Доступ к приватному полю возможен только внутри класса
    return hashFunction(this.#secretKey);
  }
}

const user = new User('Alice', 's3cr3t');
console.log(user.name); // 'Alice'
console.log(user.#secretKey); // SyntaxError: Private field '#secretKey' must be declared in an enclosing class
console.log(user.getKeyHash()); // Работает

2. Замыкания (Closures) в конструкторе функции или фабрике: Классический прием, обеспечивающий настоящую приватность.

function createUser(name) {
  let _password = ''; // Приватная переменная, доступная только через замыкание

  return {
    name: name,
    setPassword: (pw) => {
      _password = pw;
    },
    validatePassword: (pw) => {
      return _password === pw;
    }
  };
}

const user = createUser('Bob');
user.setPassword('123');
console.log(user.validatePassword('123')); // true
console.log(user._password); // undefined

3. Символы (Symbols) или WeakMaps (менее строгие методы): Эти методы скорее защищают от случайного доступа, чем от намеренного.

// С использованием WeakMap
const _privateData = new WeakMap();

class Logger {
  constructor(logLevel) {
    // Сохраняем приватные данные в WeakMap, используя экземпляр как ключ
    _privateData.set(this, { level: logLevel, internalCounter: 0 });
  }

  log(message) {
    const data = _privateData.get(this);
    data.internalCounter++;
    console.log(`[${data.level}] ${message} (call #${data.internalCounter})`);
  }
}

Вывод: Да, скрыть поля можно. Для современного кода на Node.js используйте синтаксис приватных полей класса (#field). Для максимальной изоляции в функциональном стиле подходят замыкания.

Ответ 18+ 🔞

Ну вот, сидишь ты такой, пишешь на JavaScript, и вдруг — бац! — тебе понадобилось спрятать какие-то данные, чтобы не торчали, как хуй с горы, на всеобщее обозрение. А в языке-то, ёпта, такого private как в нормальных языках — нету! Ну, терпения ноль, ебать. Но русский программист не сдаётся, есть несколько хитрых жоп, которые можно провернуть.

1. Приватные поля класса (современная фигня, ES2022): Это сейчас самый правильный и чистый способ, чтобы не позориться. Просто ставишь решётку перед именем поля, и всё — оно становится как секрет в твоей голове, никому не доступно.

class User {
  #secretKey; // Вот это приватное, его снаружи не видно
  name;      // А это — публичное, торчит наружу

  constructor(name, key) {
    this.name = name;
    this.#secretKey = key;
  }

  getKeyHash() {
    // А внутри класса — пожалуйста, юзай на здоровье
    return hashFunction(this.#secretKey);
  }
}

const user = new User('Alice', 's3cr3t');
console.log(user.name); // 'Alice' — ок
console.log(user.#secretKey); // А тут будет SyntaxError, потому что поле приватное, иди нахуй
console.log(user.getKeyHash()); // А так — работает, потому что метод публичный

2. Замыкания (Closures) — старый добрый дедовский способ: Тут всё просто, как три копейки. Создаёшь функцию, внутри неё переменная живёт своей жизнью, и снаружи к ней не подкопёшься. Настоящая приватность, ёба!

function createUser(name) {
  let _password = ''; // Вот эта переменная — как в бункере, только через замыкание

  return {
    name: name,
    setPassword: (pw) => {
      _password = pw;
    },
    validatePassword: (pw) => {
      return _password === pw;
    }
  };
}

const user = createUser('Bob');
user.setPassword('123');
console.log(user.validatePassword('123')); // true — проверка работает
console.log(user._password); // undefined — потому что снаружи её нихуя нет, вот и вся магия

3. Символы (Symbols) или WeakMaps — для тех, кто любит полумеры: Эти методы — они как мартышлюшка: вроде и защищают, но если очень захотеть, то можно обойти. Скорее от случайного доступа, чем от злостного взлома.

// Вариант с WeakMap
const _privateData = new WeakMap();

class Logger {
  constructor(logLevel) {
    // Кидаем все приватные данные в WeakMap, используя сам экземпляр как ключ
    _privateData.set(this, { level: logLevel, internalCounter: 0 });
  }

  log(message) {
    const data = _privateData.get(this);
    data.internalCounter++;
    console.log(`[${data.level}] ${message} (call #${data.internalCounter})`);
  }
}

Итог, бля: Да, спрятать поля можно, хоть и не так прямо, как хотелось бы. Если пишешь на чём-то современном и для Node.js — смело юзай приватные поля с решёткой (#field). Если ты фанат функциональщины и хочешь полной изоляции — тебе в замыкания. Главное — не выставляй наружу то, что не нужно, а то будет тебе хиросима в коде.