如何在javascript中定义私有构造函数?

时间:2014-02-10 00:28:37

标签: javascript

我在JS中定义了纯对象,它暴露了某些静态方法,这些方法应该用来构造它们而不是构造函数。如何在Javascript中为我的类创建私有的构造函数?

var Score = (function () {

  // The private constructor
  var Score = function (score, hasPassed) {
      this.score = score;
      this.hasPassed = hasPassed;
  };

  // The preferred smart constructor
  Score.mkNewScore = function (score) {
      return new Score(score, score >= 33);
  };

  return Score;
})();

更新:解决方案仍然允许我测试x instanceof Score。否则,@ user2864740解决方案只暴露静态构造函数。

4 个答案:

答案 0 :(得分:10)

可以在闭包内部使用变量(initializing),如果直接调用构造函数而不是通过类方法,则会抛出错误:

var Score = (function () {
  var initializing = false;

  var Score = function (score, hasPassed) {
      if (!initializing) {
         throw new Error('The constructor is private, please use mkNewScore.');
      }

      initializing = false;
      this.score = score;
      this.hasPassed = hasPassed;
  };

  Score.mkNewScore = function (score) {
      intializing = true;
      return new Score(score, score >= 33);
  };

  return Score;
})();

答案 1 :(得分:5)

只是不公开构造函数。原始代码的核心问题是“静态方法”被定义为构造函数的属性(用作“类”),而不是模块的属性。

考虑:

return {
    mkNewScore: Score.mkNewScore
    // .. and other static/module functions
};

仍然可以通过.constructor访问构造函数,但是.. meh。此时,不妨让“聪明的用户”有权访问。

return {
    mkNewScore: function (score) {
        var s = new Score(score, score >= 33);
        /* Shadow [prototype]. Without sealing the object this can
           be trivially thwarted with `del s.constructor` .. meh.
           See Bergi's comment for an alternative. */
        s.constructor = undefined;
        return s;
    }
};

答案 2 :(得分:5)

  

是否有解决方案可以让我说x instanceof Score

是。从概念上讲,@ user2864740是正确的,但要使instanceof工作,我们需要公开(return)函数而不是普通对象。如果该函数与我们的内部私有构造函数具有相同的.prototype,则instanceof operator执行预期的操作:

var Score  = (function () {

  // the module API
  function PublicScore() {
    throw new Error('The constructor is private, please use Score.makeNewScore.');
  }

  // The private constructor
  var Score = function (score, hasPassed) {
      this.score = score;
      this.hasPassed = hasPassed;
  };

  // Now use either
  Score.prototype = PublicScore.prototype; // to make .constructor == PublicScore,
  PublicScore.prototype = Score.prototype; // to leak the hidden constructor
  PublicScore.prototype = Score.prototype = {…} // to inherit .constructor == Object, or
  PublicScore.prototype = Score.prototype = {constructor:null,…} // for total confusion :-)

  // The preferred smart constructor
  PublicScore.mkNewScore = function (score) {
      return new Score(score, score >= 33);
  };

  return PublicScore;
}());

> Score.mkNewScore(50) instanceof Score
true
> new Score
Error (…)

答案 3 :(得分:0)

另一种可能的简单方法是使用谓词函数而不是instanceof。对于打字稿,它可以是类型防护,并且可以导出类型同义词而不是类:

// class is private
class _Score {
  constructor() {}
}

export type Score = _Score

export function isScore(s): s is Score {
  return s instanceof _Score
}