marisbest2
marisbest2

Reputation: 1356

Javascript: Inherit method from base class and return the subclass's private variable

I have the following BaseClass defined:

function BaseClass (arg1,arg2,arg3) {
    //constructor code here then - 
    var privateVar = 7500;
    this.getPrivateVar = function() { return privateVar; };
}

I want to have the following subclass which allows changing privateVar like so:

function SubClass (arg1,arg2,arg3,privateVar) {
    //constructor code here then - 
    var privateVar = privateVar;
}
SubClass.prototype = new BaseClass();

Now I want SubClass to inherit the getPrivateVar method. However, when I try this, it always returns 7500 which is the value in the BaseClass and not the value of privateVar.

In other words, is it possible to inherit a BaseClass's public methods but have any references in them refer to the SubClass's properties? And how would I do that?


By the sound of things, it's impossible. The idea was to automate a code-checker for my students code (I tutor kids) but I'll just have to find another way. Thanks anyway.

Upvotes: 1

Views: 3471

Answers (6)

Aadit M Shah
Aadit M Shah

Reputation: 74204

The idea of having a private variable is that is should not be accessible outside of the scope in which is was declared. However there are a few ways to achieve what you wish to do. For example, you could make the default value of privateVar in BaseClass dynamic:

function BaseClass(arg1,arg2,arg3) {
    var privateVar = BaseClass.privateVar;

    this.getPrivateVar = function () {
        return privateVar;
    };
}

BaseClass.privateVar = 7500;

Now you can create SubClass as follows:

function SubClass(arg1, arg2, arg3, privateVar) {
    var args = Array.prototype.slice.call(arguments, 0, 3); // the first 3 args
    var defaultPrivateVar = BaseClass.privateVar;           // save the old value
    BaseClass.privateVar = privateVar;                      // set a new default
    BaseClass.call(this, args);                             // call super
    BaseClass.privateVar = defaultPrivateVar;               // restore old value
}

SubClass.prototype = Object.create(BaseClass.prototype);    // inherit new way

Now all you need to do is simply create an instance of SubClass: http://jsfiddle.net/Pytkj/

Upvotes: 2

Bergi
Bergi

Reputation: 664297

inherit a BaseClass's public methods but have any references in them refer to the SubClass's properties?

No, that's impossible. The method created inside the BaseClass constructor scope will always reference the variables from that scope, you cannot change it. It's a variable, not a property of the object.

However, you're doing the inheritance wrong. You have a BaseClass instance from which you inherit and with which all SubClass instances will share their getPrivateVar method. Get them an own one! To do so, you can apply the parent constructor on the child instance, creating a new closure scope and a new method. And don't use new!

function SubClass (arg1,arg2,arg3) {
    BaseClass.call(this);
}
// or, if you need a reference to the variable:
function SubClass (arg1,arg2,arg3) {
    // you have to create it on your own
    var privateVar = arguments[3]; // or use a formal parameter
    // and create `getPrivateVar` yourself
    this.getPrivateVar = function() { return privateVar; };
}

SubClass.prototype = Object.create(BaseClass.prototype);

Upvotes: 0

Esailija
Esailija

Reputation: 140210

You are mixing Javascript object model with scoped variables which do not interoperate*.

The inherits idiom of doing SubClass.prototype = new BaseClass(); only works when you are using prototypes and constructors naturally:

function BaseClass(arg1, arg2, arg3) {
    this._privateVar = 7500;
}
BaseClass.prototype.getPrivateVar = function() {
    return this._privateVar;
};

function SubClass(arg1, arg2, arg3, privateVar) {

}
SubClass.prototype = new BaseClass();
//Better way to do it is 
//SubClass.prototype = Object.create(BaseClass.prototype);
SubClass.prototype.constructor = SubClass;

Before you argue that anyone can access the property by just writing _, I could argue back that anyone can access any private in Java, PHP or C# by using reflection. Or using instance_eval or send in Ruby and so on. So it's out of your hands anyway.


*None or most of these don't work when you use scoped variables depending on implementation:

  • Enumerability
  • Writability
  • First-class Accessors
  • Sealedness, Frozedness and state of Extension
  • Reflection through getPropertyNames or keys
  • instanceof operator
  • Generic methods
  • Inheritance

Upvotes: 3

fdreger
fdreger

Reputation: 12495

You would not. And even if you could, the property could not be called "private" any more. Maybe "protected".

Languages that lack different access levels just use public attributes and some sort of a naming convention (like calling them __semiPrivateVar).

There are some different solutions, but they are not really describable in terms of OO (what you really have are not classes and attributes but constructors, scopes and variables).

Upvotes: 0

sixFingers
sixFingers

Reputation: 1295

The way you defined privateVar makes it a local variable inside the scope of BaseClass "constructor". Like Neal said, you cannot inherit nor "see" it from any inherited class. You can use a closure like Neal said (but this can be a memory overkill depending on your usage context), or make the variable an instance variable:

function BaseClass (arg1,arg2,arg3) {
    //constructor code here then - 
    this.privateVar = 7500;
    this.getPrivateVar = function() { return this.privateVar; };
}

function SubClass (arg1,arg2,arg3,privateVar) {
    //constructor code here then - 
    this.privateVar = privateVar;
}

SubClass.prototype = new BaseClass();

var subClass = new SubClass(1,2,3,4000);

console.log(subClass.getPrivateVar());

Upvotes: 2

Naftali
Naftali

Reputation: 146302

privateVar is a local variable of BaseClass. It cannot be inherited or changed by the subclass.

You can encapsulate the parent and subclass in the same scope like so:

(function(){
    var privateVar = 7500;

    function BaseClass (arg1,arg2,arg3) {
        //constructor code here then - 
        this.getPrivateVar = function() { return privateVar; };
    }

    function SubClass (arg1,arg2,arg3,privateVar) {
        //constructor code here then - 
    }

    SubClass.prototype = new BaseClass();

    return SubClass;
})();

Upvotes: 0

Related Questions