我在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解决方案只暴露静态构造函数。
答案 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
}