10

I am using a closure to create an object with private and public methods. It looks like this -

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;
})();

But now I would like to have an object that has only private functions and that is inherited by another object. But is this possible in JavaScript?

Paul
  • 23,002
  • 11
  • 77
  • 112
csss
  • 1,779
  • 2
  • 12
  • 21
  • 1
    What is this `function Dog = (function() {})()`? – Amberlamps Jul 15 '13 at 10:35
  • 2
    `private` members are visible _only_ inside a class where they are defined in _any_ language that supports OOP. I don't get what you're trying to do. – Leri Jul 15 '13 at 10:40
  • In general no, but your "private function" is easily accessable via `notSoPrivateSaySize = new Dog().publicSaySize();` – Bergi Jul 15 '13 at 10:40
  • How can an object only have private functions (and still be useful)? Please show that to us. – Bergi Jul 15 '13 at 10:42
  • 3
    OP wants protected members – nice ass Jul 15 '13 at 10:42
  • @Bergi Yes I know, I was demonstrating how public functions can call private functions, which is of course necessary or there is no point to a private function. – csss Jul 15 '13 at 10:52
  • @Bergi: I want to have a base object of private functions such as validation logic that should not be exposed publically. I would then like to have some objects with public methods inherit from this object and they can make calls to the private methods in their public methods. – csss Jul 15 '13 at 10:54
  • @csss They are called as `protected` methods. Read about access modifiers. – Leri Jul 15 '13 at 10:56
  • @PLB I know about access modifiers. But I didn't know if it was correct to say protected members in a JavaScript context but if it makes things clearer then yes I'm looking for protected members. Can they be done in JavaScript? – csss Jul 15 '13 at 10:58
  • I guess not possible. And even if it's it would be really dirty workaround. – Leri Jul 15 '13 at 11:00
  • Take a look at [mootools implementation of what you want](http://mootools.net/docs/core/Class/Class). – Leri Jul 15 '13 at 11:06

5 Answers5

8

No, You can't.

JavaScript inheritance is prototype based, so You can "extend" only methods in prototype.

Radosław Miernik
  • 3,616
  • 8
  • 32
  • 34
  • Agreed. Although it is worth noting that many JS developers compromise by just prefixing otherwise public methods with an underscore to signal that they are protected or otherwise not part of the public API. Developers can choose to modify them if they wish, but that's a their own risk. To be honest, trying to secure a publicly accessible object in JS is a fairly futile endeavour, as anyone who uses your library can just overwrite any public functionality, or even scramble shared objects/prototypes. It just doesn't seem worth the headaches. – Alexis Beingessner Jul 15 '13 at 14:31
5

The privacy of variables (functions) in JavaScript is done via function scopes. You can access them from outside only if they are exported from the closure scope, there is no other way.

To make an object whose methods have access to the private functions, you will just have to place it in the same scope. Whether the object is one that inherits from other objects is quite irrelevant.

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();
Aadit M Shah
  • 67,342
  • 26
  • 146
  • 271
Bergi
  • 513,640
  • 108
  • 821
  • 1,164
2

Kind of... As Bergi points out, access is defined by scope so if you define the inheritor inside the immediate of the parent you can get roughly what you want.

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());

Not sure why you would want to though... :D

Andrew
  • 668
  • 5
  • 12
1

You want one instance to inherit the private state of another instance? Sure you can do this in JavaScript. First we need to define a utility function:

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

Now we can create our base class as follows:

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;
}());

Now you can create a dog as follows:

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

We can inherit the private state as follows:

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;
}());

Now you can create a chihuahua as follows:

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

See the demo: http://jsfiddle.net/b3Eyn/

Note: I wrote this answer just to show that it's possible to inherit private state in JavaScript. However I would advise you not to use this pattern. If you design your code well then you won't need to inherit private state in the first place.

Aadit M Shah
  • 67,342
  • 26
  • 146
  • 271
0

You can avoid the use of dot notation. But it's not truly private.

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;
})()
boskop
  • 461
  • 6
  • 7
  • To denote the "internality" of a property, the underscore `_` is used not the minus. That way you can avoid bracket notation… – Bergi Jul 15 '13 at 11:37
  • @Bergi That's the point. I used a minus because that way you can't use the dot notation, so it is only avaiable using bracket notation. – boskop Jul 15 '13 at 13:02
  • And how does that help? The [convention is to use underscores](http://stackoverflow.com/q/4484424/1048572) for denoting privacy. Bracket notation does not change anything. – Bergi Jul 15 '13 at 13:07
  • @Bergi I Know and I'm not questioning that. I'm refering to the visibility of the method using only dot notation. I Know it is a dirty solution and only solves the problem of visibility partially, but it is part of the object, so the method can be inherited by another object. – boskop Jul 15 '13 at 13:20
  • What do you mean by "visibility"? Are you referring to the appearance of the source code (which is different with bracket notation)? – Bergi Jul 15 '13 at 13:31
  • @Bergi You can't do `myDog.-privateSaySize`, because the minus is an illegal character used in this context. When using an javascript object, the bracket notation is not commonly used to access functions or properties, so this way you avoid the use of that function when using the dot notation, which is the most commonly used. – boskop Jul 15 '13 at 13:54
  • I wouldn't avoid it, but say "crazy dev, why a minus?" and switch to bracket notation. Better use the underscore, which has a *meaning* to the user. – Bergi Jul 15 '13 at 13:57