Tôi biết rằng đã hơn 1 thập kỷ kể từ khi điều này được hỏi, nhưng tôi chỉ suy nghĩ về điều này lần thứ n trong cuộc đời lập trình viên của mình và tìm thấy một giải pháp khả thi mà tôi chưa biết nếu tôi hoàn toàn thích . Tôi chưa thấy phương pháp này được ghi lại trước đây, vì vậy tôi sẽ đặt tên cho nó là "mẫu đô la riêng tư / công khai" hoặc mẫu _ $ / $ .
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]);
Khái niệm này sử dụng một ClassDefinition hàm trả về một Constructor hàm trả về một giao diện đối tượng. Phương thức duy nhất của giao diện là $nhận một nameđối số để gọi hàm tương ứng trong đối tượng hàm tạo, bất kỳ đối số bổ sung nào được truyền sau khi nameđược truyền trong lệnh gọi.
Hàm trợ giúp được xác định toàn cục ClassValueslưu trữ tất cả các trường trong một đối tượng khi cần. Nó xác định _$chức năng để truy cập chúng bằng cách name. Điều này tuân theo một mẫu get / set ngắn để nếu valueđược thông qua, nó sẽ được sử dụng làm giá trị biến mới.
var ClassValues = function (values) {
return {
_$: function _$(name, value) {
if (arguments.length > 1) {
values[name] = value;
}
return values[name];
}
};
};
Hàm được định nghĩa toàn cục Interfacesẽ lấy một đối tượng và một Valuesđối tượng để trả về một _interfacehàm duy nhất $kiểm tra objđể tìm một hàm được đặt tên theo tham số namevà gọi nó valueslà đối tượng có phạm vi . Các đối số bổ sung được truyền vào $sẽ được truyền vào lời gọi hàm.
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;
};
Trong mẫu dưới đây, ClassXđược gán cho kết quả của ClassDefinition, đó là Constructorchức năng. Constructorcó thể nhận được bất kỳ số lượng đối số. Interfacelà những gì mã bên ngoài nhận được sau khi gọi hàm tạo.
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;
}());
Không có điểm nào trong việc có các hàm không được tạo nguyên mẫu Constructor, mặc dù bạn có thể định nghĩa chúng trong thân hàm hàm tạo. Tất cả các chức năng được gọi với mô hình đô la công khai this.$("functionName"[, param1[, param2 ...]]) . Các giá trị riêng được truy cập với mẫu đô la riêng this._$("valueName"[, replacingValue]); . Như Interfacekhông có định nghĩa cho _$, các giá trị không thể được truy cập bởi các đối tượng bên ngoài. Vì mỗi thân hàm được tạo nguyên mẫu thisđược đặt thành valuesđối tượng trong hàm $, bạn sẽ có ngoại lệ nếu bạn gọi trực tiếp các hàm anh chị em của Trình xây dựng; mẫu _ $ / $ cũng cần phải được theo dõi trong các thân hàm nguyên mẫu. Dưới đây sử dụng mẫu.
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");
Và đầu ra giao diện điều khiển.
classX1.valA is invalid.
classX1.valA: undefined
classX1.valA is valid.
classX1.valA: v1
classX2.valA: v2
Mẫu _ $ / $ cho phép bảo mật hoàn toàn các giá trị trong các lớp được tạo mẫu đầy đủ. Tôi không biết liệu tôi có bao giờ sử dụng nó hay không, nếu nó có sai sót, nhưng này, nó là một câu đố hay!