Как определить частные конструкторы в javascript?
Я определил чистые объекты в JS, которые выставляют определенные статические методы, которые должны использоваться для их построения вместо конструктора. Как я могу создать конструктор для моего класса private в 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 об экспонировании только статического конструктора.
Ответы
Ответ 1
Есть ли решение, которое позволит мне сказать x instanceof Score
?
Да. Понятно, что @user2864740 прав, но для instanceof
для работы нам нужно выставить (return
) функцию вместо простого объекта. Если эта функция имеет тот же .prototype
, что и наш внутренний частный конструктор, оператор instanceof
делает то, что ожидается:
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 (…)
Ответ 2
Можно использовать переменную (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;
})();
Ответ 3
Просто не выставляйте функцию конструктора. Основной проблемой с исходным кодом является "статический метод", который определяется как свойство конструктора (которое используется как "класс" ), в отличие от свойства модуля.
Рассмотрим:
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 comment for an alternative. */
s.constructor = undefined;
return s;
}
};