Vandervals
Vandervals

Reputation: 6054

How to inherit private variables in javascript with Object.create

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.

Upvotes: 3

Views: 1374

Answers (3)

aarti
aarti

Reputation: 2865

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

Upvotes: 1

ecarrizo
ecarrizo

Reputation: 2809

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

Upvotes: 5

Paul S.
Paul S.

Reputation: 66334

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

Upvotes: 2

Related Questions