Подтвердить что ты не робот

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, потому что для того, чтобы наследование прототипа работало, оно должно быть частью прототипа.

Вопрос: Как я могу вызвать частную функцию из функции прототипа? Или в более общем смысле: когда объект (дочерний объект) наследует от другого объекта (родительский объект), как следует использовать методы-пользователи с помощью вспомогательных функций и возможно ли сделать их частными?

4b9b3361

Ответ 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();