Вопросы о WeakMap и приватных переменных - PullRequest
1 голос
/ 13 октября 2019

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

const Car = (function() {
  const carProps = new WeakMap();
  class Car {
    constructor(make, model) {
      this.make = make;
      this.model = model;
      this._userGears = ["P", "N", "R", "D"];
      carProps.set(this, { userGear: this._userGears[0] });
    }
    get userGear() {
      return carProps.get(this).userGear;
    }
    set userGear(value) {
      if (this._userGears.indexOf(value) < 0)
        throw new Error(`Invalid gear: ${value}`);
      carProps.get(this).userGear = value;
    }
    shift(gear) {
      this.userGear = gear;
    }
  }
  return Car;
})();

Я не могу понять, как такой код может действительно сделать механизмсвойство private и не разрешает доступ извне.

кажется, что, используя

carProps.set(this, { userGear: this._userGears[0] });

, мы скрываем userGear и делаем его приватным, чтобы к нему нельзя было получить доступ.

Однако, когда я использую

const car1 = new Car("Toyota", "Prius");
console.log(car1);
console.log(car1.userGear);

, он показывает мне результат

Car {
  make: 'Toyota',
  model: 'Prius',
  _userGears: [ 'P', 'N', 'R', 'D' ] }
P

Я не уверен, почему я мог получить доступ к userGear и получил 'P' вместо 'undefined'здесь, где предполагается, что он недоступен.

Возможно, я делаю что-то неправильно или неправильно понял концепцию.

Может кто-нибудь помочь мне разобраться в WeakMap?

1 Ответ

2 голосов
/ 13 октября 2019

Получатель и установщик userGear, показанные в коде, как раз там, чтобы показать вам, как вы можете взаимодействовать между (приватным) carProps внутри класса и внешней областью видимости. Цель этого примера - показать, что переменная carProps не может быть доступна, кроме как с помощью преднамеренно раскрытых методов userGear. Если эти методы не существуют, то после установки WeakMap в конструкторе внешний потребитель Car не сможет что-либо увидеть или сделать с ним, например:

const Car = (function() {
  const carProps = new WeakMap();
  class Car {
    constructor(make, model) {
      this.make = make;
      this.model = model;
      this._userGears = ["P", "N", "R", "D"];
      carProps.set(this, { userGear: this._userGears[0] });
    }
    shift(gear) {
      this.userGear = gear;
    }
  }
  return Car;
})();

const car = new Car('foo', 'bar');
// at this point, at this level of scope,
// there is no way for a user of "car" or "Car" to reference carProps
console.log(car.userGear);

В качестве другого примера, который может иметь больше смысла, скажем, что конструктор выбрал случайное число, которое угадал пользователь класса:

const Game = (function() {
  const gameProps = new WeakMap();
  return class Game {
    constructor() {
      gameProps.set(this, { randomNum: Math.floor(Math.random() * 10) });
    }
    guess(num) {
      return gameProps.get(this).randomNum === num ? 'Win' : 'Lose';
    }
  }
})();

const game = new Game();
// at this point, at this level of scope,
// there is no way for a user of "Game" or "game" to reference gameProps
// or to figure out the random number, without guessing multiple times
console.log(
  game.guess(1),
  game.guess(2),
  game.guess(3),
  game.guess(4),
  game.guess(5)
);

С помощью приведенного выше кода вызывающий Game не сможет выяснить внутреннее случайное число в игре без вызова (преднамеренно раскрытого метода) .guess несколькораз. (если только Math.random не получат обезьяну заранее) ...

...