Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to define private constructors in javascript?

Tags:

I have defined pure objects in JS which expose certain static methods which should be used to construct them instead of the constructor. How can I make a constructor for my class private in 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;
})();

Update: The solution should still allow me to test for x instanceof Score. Otherwise, the solution by @user2864740 of exposing only the static constructor works.

like image 393
musically_ut Avatar asked Feb 10 '14 00:02

musically_ut


People also ask

How do you make a constructor private in JavaScript?

How can I make a constructor for my class private in Javascript? var Score = (function () { // The private constructor var Score = function (score, hasPassed) { this. score = score; this.

Can we define private constructor?

Yes, we can declare a constructor as private. If we declare a constructor as private we are not able to create an object of a class. We can use this private constructor in the Singleton Design Pattern.

How do I create a private constructor?

Java allows us to declare a constructor as private. We can declare a constructor private by using the private access specifier. Note that if a constructor is declared private, we are not able to create an object of the class. Instead, we can use this private constructor in Singleton Design Pattern.

How do you define a private function in JavaScript?

In a JavaScript class, to declare something as “private,” which can be a method, property, or getter and setter, you have to prefix its name with the hash character “#”.


2 Answers

One can use a variable (initializing) inside a closure which can throw an error if the constructor was called directly instead of via a class method:

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;
})();
like image 66
musically_ut Avatar answered Oct 02 '22 13:10

musically_ut


Is there a solution which will allow me to say x instanceof Score?

Yes. Conceptually, @user2864740 is right, but for instanceof to work we need to expose (return) a function instead of a plain object. If that function has the same .prototype as our internal, private constructor, the instanceof operator does what is expected:

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 (…)
like image 41
Bergi Avatar answered Oct 02 '22 13:10

Bergi