Могу ли я "расширить" класс, определенный закрытием, в Javascript?

У меня есть "класс" Javascript, определенный следующим образом:

var Welcomer = function(name) {
  var pName = name;
  var pMessage = function() {
    return "Hi, " + pName + "!";
  };

  return {
    sayHi: function() {
      alert(pMessage());
    }
  };
};

new Welcomer('Sue').sayHi();

Есть ли способ "подкласса" Welcomer таким образом, чтобы я мог переопределять общедоступные методы и иметь доступ к частным методам и переменным? Следующее даст мне доступ к публичным методам, но не к частным:

var UnhappyWelcomer = function(name) {
  var pSadMessage = function() {
    // won't work, b/c I don't have access to pMessage
    return pMessage() + " Miserable day, innit?";
  };

  return {
    sayHi: function() {
      alert(pSadMessage());
    }
  };
};
UnhappyWelcomer.prototype = Welcomer(); // failed attempt at inheritance

new UnhappyWelcomer().sayHi();

Ответ 1

Простой ответ на ваш вопрос: Нет.

Вы не можете ничего сделать, чтобы получить доступ к тем var определенным вещам, если только ваша функция не находится в одной области, или вы каким-либо образом публикуете эту информацию (возвращая ее или устанавливая ее на this).

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

var Welcomer = function(name) {
  var _protected = {
    name: name,
    message: function() {
      return "Hi, " + _protected.name + "!";
    }
  };

  return {
    extendWith: function(extender) {
      extender.call(this, _protected);
      return this;
    },
    sayHi: function() {
      alert(_protected.message());
    }
  };
};

var UnhappyWelcomer = function(name) {
  var self = Welcomer(name).extendWith(function(_protected) {
    _protected.sadMessage = function() {
       return _protected.message() + " Miserable day, innit?";
    };
    // extending the public while still having scope to _protected...
    this.sayHi = function() {
      alert(_protected.sadMessage());
    };
  });
  return self;
};

UnhappyWelcomer('bob').sayHi();

Ответ 2

Этот шаблон "class" не является "классом", он известен как Module Pattern. Он возвращает объект, который не связан с функцией, создавшей ее, а затем доступ к ней из частных переменных. Возвращаемый объект НЕ является экземпляром функции, которая его создала.

Когда вы вызываете "новый класс()", он создает экземпляр этой функции, но также возвращает другой объект. Любые дальнейшие операции на самом деле находятся на возвращенном объекте, а не на экземпляре.

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

Дальнейшее чтение:

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

Как только вы узнаете больше об этом, вы, скорее всего, проигнорируете частных членов alltogether и используете префикс _ и просто сделаете его публичным пользователем, как и все остальные;) Это просто проще, а частные члены бессмысленны.

Ответ 3

Если вам действительно нужно наследование, там есть несколько библиотек, которые очень помогут. Один из вариантов - trait.js, который в любом случае может стать стандартной частью javascript. Если это не плавает на вашей лодке, библиотеки, такие как jQuery и прототип, имеют помощники для наследования.

Если вы хотите пойти с минимальным/от нуля, я настоятельно рекомендую вам использовать прототип модели для всего. Вы увидите большое увеличение производительности по сравнению с шаблоном, который у вас есть в ваших примерах.

Чтобы более непосредственно обратиться к вашему вопросу, нет. У вас будет более легкое время, если вы создадите свои "классы", поэтому частные функции не зависят.