1

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.

marisbest2
  • 1,346
  • 2
  • 17
  • 30

6 Answers6

3

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
Esailija
  • 138,174
  • 23
  • 272
  • 326
2

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());
sixFingers
  • 1,285
  • 8
  • 13
  • Btw, you are not saving any memory this way. The function must be defined outside. The problem is that functions in Javascript are first-class, so anytime you mention `function(){}`, you need to create the function object - even with code sharing the object is expensive and what causes the heavy use of memory. – Esailija Aug 02 '13 at 15:48
  • I wanted to hint at the fact that closures force the engine to keep in memory the state of the local scope. In this case, there's no scope persistence, and, for sure, at least one function call less. Moreover, in this case, using a closure makes the var completely static. – sixFingers Aug 02 '13 at 15:58
  • Yes but even one function object already has more overhead than having to create context object. With 30 methods, you create 30 of those. The context object is a bucket in the ocean compared to function objects, which you can avoid creating by simply moving them outside. – Esailija Aug 02 '13 at 16:10
2

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/

Aadit M Shah
  • 72,912
  • 30
  • 168
  • 299
0

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;
})();
Naftali
  • 144,921
  • 39
  • 244
  • 303
0

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).

fdreger
  • 12,264
  • 1
  • 36
  • 42
0

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);
Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • You say he is doing inheritance wrong, and then move everything from the baseclass to the subclass and thus don't inherit anything. And if you tried to inherit from SubClass now, it would not work because the methods will be always tied to a specific instance instead of being generic. :I – Esailija Aug 02 '13 at 15:52