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 name
argumen untuk memanggil fungsi yang sesuai dalam objek konstruktor, setiap argumen tambahan yang diteruskan setelah name
diteruskan dalam doa.
Fungsi helper yang didefinisikan secara global ClassValues
menyimpan semua bidang dalam suatu objek sesuai kebutuhan. Ini mendefinisikan _$
fungsi untuk mengaksesnya name
. Ini mengikuti pola get / set pendek jadi jika value
dilewatkan, 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 Interface
mengambil objek dan Values
objek untuk mengembalikan sebuah _interface
dengan satu fungsi tunggal $
yang memeriksa obj
untuk menemukan fungsi yang dinamai parameter name
dan memanggilnya dengan values
sebagai 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, ClassX
ditugaskan untuk hasil ClassDefinition
, yang merupakan Constructor
fungsinya. Constructor
dapat menerima sejumlah argumen. Interface
adalah 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 Interface
tidak memiliki definisi untuk _$
, nilai tidak dapat diakses oleh objek eksternal. Karena masing-masing fungsi tubuh prototipe this
diatur ke values
objek 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!