3

I have this:

function Book (){
  this.width = 7;
  this.height = 10;
  var pages = 100;

  this.tear_page = function(){
    return --pages;
  }
}
function TechBook () {
  var pages = 50;
  this.open_book = function(){ return "Opened in page "+(pages/2); };
  return this;
}
var bBook = Object.create(new Book(), new TechBook());


console.log(bBook);
console.log(bBook.tear_page());
console.log(bBook.open_book());

I can't get this to work. I got as far as getting TechBook to inherit the access to local/private variables from Book but only from the Book functions. If I add new methods or overwrite them, they can't get those variables any more. I wonder if there is a way to still have access to those variables from methods of the subclass and to create new private variables inside the subclass.

If this is not posible in any way, that would mean that you can't have private variables if you want inheritage, or viceversa. Oh, and btw, I know that chrome can now (thanks to ES6) implement classes naturally with: class TechBook extends Book (){} as many other languages, but as support is limited to last versions of chrome at this time... I wonder if there is any other way to solve this problem.

Vandervals
  • 5,774
  • 6
  • 48
  • 94
  • 5
    You're trying to take classical concepts and apply them to _JavaScript_, and they just don't apply here. There is no such thing as "public" or "private" in _JavaScript_, just **closure** – Paul S. Apr 30 '15 at 16:14
  • 1
    While closures could be used to emulate **privacy**, as long as I am aware, there is no way to have **protected** members. And this is really what you want. Private members are never inherited, this would not work in Java/C# or any other oo language. And last thing, ES6 classes don't have protected members, too. – Wiktor Zychla Apr 30 '15 at 16:21
  • Your `bBook = Object.create(new Book(), new TechBook())` code is totally messed up. See [here](http://stackoverflow.com/a/10898859/1048572) for doing inheritance properly (and then use `bBook = new TechBook();` for instantiation). – Bergi Apr 30 '15 at 16:22
  • @Vandervals: You have however overwrite the public methods that access the private variable… – Bergi Apr 30 '15 at 16:25
  • Languages with inheritance never grant you access to you private variables. Private means that... is private in the context that they are and no one can access it outside of that context. – ecarrizo Apr 30 '15 at 16:36

3 Answers3

5

You can't inherit private in any language, only protected or public can be inherited.

That concept does not exist in javascript but u can emulate when creating an object (properties = public, scope things = private);

A work around could be add a property that execute a function that return the private variable/function of the object scope.

If expose a method that return a private object it can be modified because u have the returned reference.

I like to do it like this:

var SomeObject = function() {
    //private var one, can't access it outside of this scope
    var one = 1;

    /*private object anotherObject, can't access it directly
     but if you return it with a public function you can modify it.*/
    var anotherObject = {
        a : 'somevalue'
    };

    //public prop two, can access it outside of this scope.
    this.two = 2;

    //public method getOne, you can access it.
    this.getOne = function() {
       return one;
    };

    /* return private var anotherObject */
    this.getAnotherObject = function() {
       return anotherObject;
    };
};

var someObject = new SomeObject();
console.log(someObject.two); // print in console 2
console.log(someObject.getOne()); // print in console 1

var referencedObject = someObject.getAnotherObject();
console.log(referencedObject);
referencedObject.a = 'anotherValue';

console.log(someObject.getAnotherObject());

Fiddle

ecarrizo
  • 2,758
  • 17
  • 29
  • If you use an _Object_ to hold `one` and pass that _Object_, you'll be able to modify it externally too. – Paul S. Apr 30 '15 at 16:47
  • This is very interesting but my question was about inheriting and why a subclass can access private vars but only from the "parent's" methods. Would you like to extend your answer to contemplate this before I accept an answer? – Vandervals May 04 '15 at 10:54
2

Here is an example of how you might pass data by knowing a secret

function Book(secret) {
    secret = secret || {};
    var env = {}; // `env` to hold data requiring `secret`
    this.width = 7;
    this.height = 10;
    env.pages = 100;
    this.getEnv = function (s) { // give access to `env` if you know the secret
        if (s === secret) return env;
    };
    this.tear_page = function () {
        return --env.pages;
    };
}

function TechBook(secret) {
    secret = secret || {};
    Book.call(this, secret); // construct from Book
    var env = this.getEnv(secret); // get references via secret

    this.open_book = function () {
        return "Opened in page " + (env.pages/2);
    };
}

TechBook.prototype = Object.create(Book.prototype); // set up inheritance

Using an Object reference as the secret will be more secure than using a primitive as you'll need the original reference for access.

Now you have

var bBook = new TechBook();
console.log(bBook); // instance of TechBook
console.log(bBook.tear_page()); // 99
console.log(bBook.open_book()); // Opened in page 49.5
Paul S.
  • 64,864
  • 9
  • 122
  • 138
1

Reference to fundamentals of prototype inheritance and Object.create property arguments.

Implemented based on your example

function Book (){
  this.width = 7;
  this.height = 10;
  this.pages = 100;

  this.tear_page = function(){
    return --this.pages;
  }
  this.init = function() {
    return this
  }
}

Book.prototype = {
  open_book: function(){ return "Opened in page "+(this.pages/2) }
}


var bBook = Object.create(new Book(), {pages: { value: 50 } }).init();


console.log( new Book())              // { width: 7, height: 10, pages: 100, tear_page: [Function], init: [Function] }
console.log( bBook )                  //{}
console.log( bBook.width )            //->7              
console.log( bBook.height )           //-> 10             
console.log( bBook.pages )            // -> 50             
console.log( bBook.tear_page())       //-> 49
console.log(bBook.open_book())       //-> Opened in page 25
Sevle
  • 3,109
  • 2
  • 19
  • 31
aarti
  • 2,815
  • 1
  • 23
  • 31
  • The problem with this is that when you create bBook, you are not creating a new class, but a new instance, automatically. Would it be posible to create a TechBook class that returns Object.create(new Book(), {pages: {value:50} }); on instance creation? – Vandervals May 04 '15 at 11:02
  • Add an init method to Book function and return the instance when creating inherited Object. I updated the code in my answer. – aarti May 04 '15 at 17:23