Saya tahu ini sudah lebih dari 1 dekade sejak ditanya, tetapi saya hanya memikirkan ini untuk kali ke-9 dalam kehidupan programmer saya, dan menemukan solusi yang mungkin saya tidak tahu apakah saya sepenuhnya suka belum . Saya belum pernah melihat metodologi ini didokumentasikan sebelumnya, jadi saya akan menamainya "pola dolar privat / publik" atau pola _ $ / $ .
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]);
Konsep ini menggunakan fungsi ClassDefinition yang mengembalikan fungsi Konstruktor yang mengembalikan objek Interface . Satu-satunya metode antarmuka adalah $yang menerima nameargumen untuk memanggil fungsi yang sesuai dalam objek konstruktor, setiap argumen tambahan yang diteruskan setelah namediteruskan dalam doa.
Fungsi helper yang didefinisikan secara global ClassValuesmenyimpan semua bidang dalam suatu objek sesuai kebutuhan. Ini mendefinisikan _$fungsi untuk mengaksesnya name. Ini mengikuti pola get / set pendek jadi jika valuedilewatkan, itu akan digunakan sebagai nilai variabel baru.
var ClassValues = function (values) {
return {
_$: function _$(name, value) {
if (arguments.length > 1) {
values[name] = value;
}
return values[name];
}
};
};
Fungsi yang didefinisikan secara global Interfacemengambil objek dan Valuesobjek untuk mengembalikan sebuah _interfacedengan satu fungsi tunggal $yang memeriksa objuntuk menemukan fungsi yang dinamai parameter namedan memanggilnya dengan valuessebagai objek scoped . Argumen tambahan yang diteruskan $akan diteruskan pada pemanggilan fungsi.
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;
};
Dalam sampel di bawah ini, ClassXditugaskan untuk hasil ClassDefinition, yang merupakan Constructorfungsinya. Constructordapat menerima sejumlah argumen. Interfaceadalah apa yang didapat kode eksternal setelah memanggil konstruktor.
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;
}());
Tidak ada gunanya memiliki fungsi non-prototip Constructor, meskipun Anda bisa mendefinisikannya di badan fungsi konstruktor. Semua fungsi dipanggil dengan pola dolar publik this.$("functionName"[, param1[, param2 ...]]) . Nilai-nilai pribadi diakses dengan pola dolar pribadi this._$("valueName"[, replacingValue]); . Karena Interfacetidak memiliki definisi untuk _$, nilai tidak dapat diakses oleh objek eksternal. Karena masing-masing fungsi tubuh prototipe thisdiatur ke valuesobjek dalam fungsi $, Anda akan mendapatkan pengecualian jika Anda memanggil fungsi saudara Konstruktor secara langsung; pola _ $ / $ perlu diikuti dalam badan fungsi yang di-prototip juga. Penggunaan sampel di bawah ini.
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");
Dan output konsol.
classX1.valA is invalid.
classX1.valA: undefined
classX1.valA is valid.
classX1.valA: v1
classX2.valA: v2
Pola _ $ / $ memungkinkan privasi penuh nilai di kelas yang sepenuhnya di-prototyped. Saya tidak tahu apakah saya akan pernah menggunakan ini, atau apakah itu memiliki kekurangan, tapi hei, itu adalah teka-teki yang bagus!