我知道这个问题已经被问了十多年,但是作为一名程序员,我又在第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.";
}
};
values.$ = _interface.$;
return _interface;
};
在下面的示例中,
ClassX
被赋值为
ClassDefinition
的结果,而
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() {
return this._$("valA");
};
Constructor.prototype.setValA = function setValA(valA) {
this._$("valA", valA);
};
Constructor.prototype.isValAValid = function isValAValid(validMessage, invalidMessage) {
var valA = this.$("getValA");
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"));
以及控制台输出。
classX1.valA is invalid.
classX1.valA: undefined
classX1.valA is valid.
classX1.valA: v1
classX2.valA: v2
_$/$模式允许在完全原型化的类中对值进行完全私有化。我不知道我是否会使用它,也不知道它是否存在缺陷,但是嘿,这是一个很好的难题!