Javascript: вызов частного метода из прототипа
Я уверен, что это должен быть довольно распространенный вопрос, но после протравливания интернетов в течение нескольких часов я не нашел ответа. Вот вопрос:
Предположим, что у меня есть интерфейс, называемый млекопитающим. Каждый млекопитающий должен уметь спать и есть. (В будущем я могу бросить исключения для класса Mammal, чтобы заставить детей реализовать эту функцию).
function Mammal() {};
Mammal.prototype.eat = function() {};
Mammal.prototype.sleep = function() {};
Теперь предположим, что у меня есть класс Dog, который реализует класс Mammal:
function Dog() {};
Dog.prototype = new Mammal();
Dog.prototype.eat = function() {
...
};
Dog.prototype.sleep = function() {
...
};
Функция щенка собаки очень сложна, и я хотел бы использовать вспомогательную функцию. Я не смог понять, что лучший способ сделать это. Вот точки зрения:
- Вспомогательная функция никогда не должна вызываться извне класса собаки, поэтому в идеале она должна быть частной.
- Функция eat не имеет доступа к закрытым функциям (прототипы не имеют доступа к закрытым функциям)
- Я мог бы помещать вспомогательную функцию в функцию с привилегией, но:
- Это все равно будет публичной функцией → то есть: каждый имеет право называть ее
- Это не будет частью прототипа, поэтому каждая собака должна иметь свою собственную вспомогательную функцию. Если было много собак, это кажется неэффективным.
- Я не могу сделать функцию eat функцией privaliged, потому что для того, чтобы наследование прототипа работало, оно должно быть частью прототипа.
Вопрос: Как я могу вызвать частную функцию из функции прототипа? Или в более общем смысле: когда объект (дочерний объект) наследует от другого объекта (родительский объект), как следует использовать методы-пользователи с помощью вспомогательных функций и возможно ли сделать их частными?
Ответы
Ответ 1
Определите свой Dog
"класс" в закрытии. Тогда вы можете иметь общие привилегированные функции. Просто знайте, что вам придется быть осторожным при привязке this
, когда вы его вызываете.
var Dog = (function() {
function Dog() {};
// Common shared private function, available only to Dog.
var privateHelper = function() { ... };
Dog.prototype = new Mammal();
Dog.prototype.eat = function() {
privateHelper()
// Or this if the helper needs to access the instance.
// privateHelper.call(this);
...
};
return Dog;
})();
Функция на прототипе остается функцией. Поэтому следует те же правила доступа к закрытию и закрытию, что и любая другая функция. Поэтому, если вы определяете весь свой конструктор и прототип Dog
и изолированный остров области видимости, который является функцией самоисполнения, вы можете делиться столько, сколько хотите, не подвергая воздействию или не загрязняя общедоступную область.
Именно так классы CoffeeScript сводятся к JS.
Ответ 2
Это невозможно. Если вам нужен доступ к частным переменным/функциям, вы должны использовать привилегированные (вспомогательные) функции.
Иногда можно использовать вспомогательные функции в локальной области ограничения вместо частных вспомогательных функций (в области конструктора), которые будут доступны из функций прототипа. См. Ответы Алекса Уэйна или Рейноса.
Ты сказал:
Я не могу сделать функцию eat функцией privaliged, потому что для того, чтобы наследование прототипа работало, оно должно быть частью прототипа.
Почему бы и нет?
MammalPrototype = {
eat: function() {},
sleep: function() {}
};
function Dog(color) {
...
this.eat = function() {
... // using private functions
MammalPrototype.eat.call(this, options) // ?
};
};
Dog.prototype = Object.create(MammalPrototype); // inherit from an object
new Mammal()
в порядке, когда млекопитающее действительно является пустой функцией. См. fooobar.com/questions/246178/..., как это работает. Прокладка, предложенная там, конечно, не является тем, что делает нативная реализация, но это именно то, что нам нужно здесь. Не создавайте экземпляр, чтобы наследовать его!
Dog.prototype.sleep = function() {
...
};
function Dalmatian() {
Dog.call(this, "black.white");
...
}
Dalmatian.prototype = Object.create(Dog.prototype); // sic
Dalmatian.prototype.xyz = function() {};
Вызов суперструктора на this
означает получение всех привилегированных методов и их функциональность. Вам нужно будет сделать это, если вы используете частные "переменные" и/или функции в "классах", на которые вы наследуете, иначе все вызовы унаследованных привилегированных функций будут влиять только на один экземпляр, на который вы установили prototype
.
Ответ 3
Когда объект (дочерний объект) наследует от другого объекта (родительский объект), как методы-дети используют вспомогательные функции и возможно ли сделать их частными?
Для достижения желаемого вам потребуется несколько уровней абстракции: Live Example
Использует klass
var Mammal = klass(function (privates) {
privates.local_helper = function () {
console.log("local_helper invoked");
}
return {
constructor: function () {
console.log("mammal constructed");
privates(this).caneat = true;
},
eat: function () {
privates.local_helper();
console.log("mammal eat");
},
sleep: function () {
console.log("mammal sleep");
}
};
});
var Dog = klass(Mammal, function (privates, $super) {
return {
constructor: function () {
$super.constructor.call(this);
console.log("dog constructed");
},
eat: function () {
$super.eat.call(this);
privates.local_helper();
console.log("dog eat");
console.log(privates(this).caneat);
}
};
});
var dog = new Dog();
dog.eat();