我知道自从被问到这个问题已经超过 10 年了,但我只是在我的程序员生命中第 n 次思考这个问题,并找到了一个可能的解决方案,我不知道我是否完全喜欢呢。我以前没有见过这种方法的记录,所以我将其命名为“私人/公共美元模式”或 _$ / $ 模式。
var ownFunctionResult = this.$("functionName"[, arg1[, arg2 ...]]);
var ownFieldValue = this._$("fieldName"[, newValue]);
var objectFunctionResult = objectX.$("functionName"[, arg1[, arg2 ...]]);
//Throws an exception. objectX._$ is not defined
var objectFieldValue = objectX._$("fieldName"[, newValue]);
这个概念使用一个 ClassDefinition 函数,该函数返回一个 Constructor 函数,该函数返回一个 Interface 对象。该接口的唯一方法是$,它接收name 参数以调用构造函数对象中的相应函数,在name 之后传递的任何附加参数都会在调用中传递。
全局定义的辅助函数ClassValues 根据需要将所有字段存储在an 对象中。它定义了_$ 函数以通过name 访问它们。这遵循一个简短的 get/set 模式,因此如果 value 被传递,它将被用作新的变量值。
var ClassValues = function (values) {
return {
_$: function _$(name, value) {
if (arguments.length > 1) {
values[name] = value;
}
return values[name];
}
};
};
全局定义的函数Interface 接受一个对象和一个Values 对象以返回一个_interface 和一个函数$,它检查obj 以找到一个以参数name 命名的函数并调用它以values 作为 scoped 对象。传递给$ 的附加参数将在函数调用时传递。
var Interface = function (obj, values, className) {
var _interface = {
$: function $(name) {
if (typeof(obj[name]) === "function") {
return obj[name].apply(values, Array.prototype.splice.call(arguments, 1));
}
throw className + "." + name + " is not a function.";
}
};
//Give values access to the interface.
values.$ = _interface.$;
return _interface;
};
在下面的示例中,ClassX 分配给ClassDefinition 的结果,即Constructor 函数。 Constructor 可以接收任意数量的参数。 Interface 是外部代码调用构造函数后得到的。
var ClassX = (function ClassDefinition () {
var Constructor = function Constructor (valA) {
return Interface(this, ClassValues({ valA: valA }), "ClassX");
};
Constructor.prototype.getValA = function getValA() {
//private value access pattern to get current value.
return this._$("valA");
};
Constructor.prototype.setValA = function setValA(valA) {
//private value access pattern to set new value.
this._$("valA", valA);
};
Constructor.prototype.isValAValid = function isValAValid(validMessage, invalidMessage) {
//interface access pattern to call object function.
var valA = this.$("getValA");
//timesAccessed was not defined in constructor but can be added later...
var timesAccessed = this._$("timesAccessed");
if (timesAccessed) {
timesAccessed = timesAccessed + 1;
} else {
timesAccessed = 1;
}
this._$("timesAccessed", timesAccessed);
if (valA) {
return "valA is " + validMessage + ".";
}
return "valA is " + invalidMessage + ".";
};
return Constructor;
}());
在Constructor 中使用非原型函数是没有意义的,尽管您可以在构造函数体中定义它们。所有函数都以 公共美元模式 this.$("functionName"[, param1[, param2 ...]]) 调用。私有值通过 私有美元模式 this._$("valueName"[, replacingValue]); 访问。由于Interface 没有_$ 的定义,因此外部对象无法访问这些值。由于每个原型函数体的this 都设置为函数$ 中的values 对象,因此如果直接调用Constructor 兄弟函数,则会出现异常; _$ / $ 模式 也需要在原型函数体中遵循。以下示例用法。
var classX1 = new ClassX();
console.log("classX1." + classX1.$("isValAValid", "valid", "invalid"));
console.log("classX1.valA: " + classX1.$("getValA"));
classX1.$("setValA", "v1");
console.log("classX1." + classX1.$("isValAValid", "valid", "invalid"));
var classX2 = new ClassX("v2");
console.log("classX1.valA: " + classX1.$("getValA"));
console.log("classX2.valA: " + classX2.$("getValA"));
//This will throw an exception
//classX1._$("valA");
还有控制台输出。
classX1.valA is invalid.
classX1.valA: undefined
classX1.valA is valid.
classX1.valA: v1
classX2.valA: v2
_$ / $ 模式 允许在完全原型化的类中完全保密值。我不知道我是否会使用它,也不知道它是否有缺陷,但是嘿,这是一个很好的拼图!