Можете ли вы наследовать частные функции в JavaScript?

Я использую закрытие для создания объекта с частными и общедоступными методами. Это выглядит так:

var Dog = (function() {
    function Dog() {}

    var size = 'big';

    var _privateSaySize = function() {
        return 'I am a ' + size + ' dog.';
    }

    Dog.prototype.publicSaySize = function() {
        return _privateSaySize();
    }

    return Dog;
})();

Но теперь я хотел бы иметь объект, который имеет только частные функции и наследуется другим объектом. Но возможно ли это в JavaScript?

Ответ 1

Вы хотите, чтобы один экземпляр наследовал частное состояние другого экземпляра? Конечно, вы можете сделать это в JavaScript. Сначала нам нужно определить служебную функцию:

function weakBind(functable, prototype, state) {
    return function () {
        return functable.apply(this, Object.getPrototypeOf(this) === prototype ?
            [state].concat(Array.prototype.slice.call(arguments)) : arguments);
    };
}

Теперь мы можем создать наш базовый класс следующим образом:

var Dog = (function () {
    function Dog() {
        if (this instanceof Dog) {
            // constructor code
        } else return Object.create(private);
    }

    var public = Dog.prototype, private = Object.create(public, {
        size: {
            value: "big"
        }
    });

    public.saySize = weakBind(function (private) {
        return "I am a " + private.size + " dog.";
    }, public, private);

    return Dog;
}());

Теперь вы можете создать собаку следующим образом:

var dog = new Dog;
alert(dog.saySize()); // I am a big dog.
alert(dog.size);      // undefined

Мы можем наследовать частное состояние следующим образом:

var Chihuahua = (function () {
    function Chihuahua() {
        Dog.call(this);
    }

    var private = Dog();

    Object.defineProperty(private, {
        size: {
            value: "small"
        }
    });

    var public = Chihuahua.prototype = Object.create(Dog.prototype);

    public.saySize = weakBind(public.saySize, public, private);

    return Chihuahua;
}());

Теперь вы можете создать чихуахуа следующим образом:

var chi = new Chihuahua;
alert(chi.saySize());    // I am a small dog.
alert(chi.size);         // undefined

См. демонстрацию: http://jsfiddle.net/b3Eyn/

Примечание: Я написал этот ответ, чтобы показать, что он может наследовать частное состояние в JavaScript. Однако я бы посоветовал вам не использовать эту схему. Если вы хорошо разработали код, тогда вам не нужно наследовать частное состояние в первую очередь.

Ответ 2

Нет, вы не можете.

Наследование JavaScript основано на прототипе, поэтому вы можете "расширить" только прототипы.

Ответ 3

Конфиденциальность переменных (функций) в JavaScript выполняется через области функций. Вы можете получить к ним доступ извне, только если они экспортированы из области закрытия, другого способа не будет.

Чтобы создать объект, чьи методы имеют доступ к частным функциям, вам просто нужно разместить его в той же области. Является ли объект тем, который наследует от других объектов, совершенно не имеет значения.

function Dog() {}
function Dalmatian() {}
Dalmation.prototype = Object.create(Dog.prototype);
Dalmation.prototype.size = "big";
function Dackel() {}
Dackel.prototype = Object.create(Dog.prototype);
Dackel.prototype.size = "small";

(function() {
    // private function
    function say(s) {
        console.log("I'm a "+s+" dog");
    }
    // both accessible from the Dog and Dackel public methods
    Dog.prototype.saySize = function() {
        say(this.size || "normal");
    };
    Dackel.prototype.saySize = function() {
        say(this.size + " but loud");
    };
})();
new Dog().saySize();
new Dalmatian().saySize();
new Dackel().saySize();

Ответ 4

Вид... Как указывает Берги, доступ определяется областью действия, поэтому, если вы определяете наследника внутри непосредственного родителя, вы можете получить примерно то, что хотите.

var BarkingDog;
var Dog = (function() {
    function Dog() {}

    var size = 'big';

    var _privateSaySize = function() {
        return 'I am a ' + size + ' dog.';
    };

    Dog.prototype.publicSaySize = function() {
        return _privateSaySize();
    };

    BarkingDog = (function () {
        function BarkingDog () {}

        var say = 'woof';

        BarkingDog.prototype = new Dog();

        BarkingDog.prototype.bark = function () {
            return _privateSaySize() + ' ' + say;
        };

        return BarkingDog;

    })();

    return Dog;
})();

var myDog = new BarkingDog();
console.log(myDog.bark());
console.log(myDog.publicSaySize());

Не знаю, почему вы хотели бы, хотя...: D

Ответ 5

Вы можете избежать использования точечной нотации. Но это не совсем личное.

var Dog = (function() {
    function Dog() {}

    var size = 'big';

    Dog.prototype['-privateSaySize'] = function() {
        return 'I am a ' + size + ' dog.';
    }

    Dog.prototype.publicSaySize = function() {
        return this['-privateSaySize']();
    }

    return Dog;
})()