0

I am just wondering if there is any drawbacks with the way I am tackling inheritance below ? Is there any memory leaks to consider, any more memory use than other inheritance patterns ? I prefer to code JavaScript with the "class" pattern below ( new ...() ) ... I find other inheritance patterns obtrusive, and just came up with this one...

Comments are appreciated!

// Class A
function A() {

  var that = this;

  that.hello = function() {

    return "HELLO";

  }

}

// Class B
function B() {
  var zuper = new A();
  var that = this;

  that.variable = "VARIABLE";

  zuper.bye = function () {

    return "BYE";
  }

  zuper.getVariable = function() { 
    return that.variable
  }

  return zuper;
}

var b = new B();
alert ( b.hello() ) // "HELLO"
alert ( b.bye() )   // "BYE"
alert ( b.getVariable() ) // "VARIABLE"

================================ EDIT ================================= I have revised my original way, and came up with this. Does this suffer from the same problem as the one before ( Two objects created when creating a B, ( A and B total) ) See apply call in beginning of B

// Class A
function A() {

  var that = this;
  that.publicProperty = "PUBLIC_PROPERTY";
  var privateProperty = "PRIVATE_PROPERTY";

  that.hello = function() {
    return "HELLO";
  }

  that.getPrivateProperty = function () {
     return privateProperty;
  }

  that.overrideThis = function() {
    return "NO_PLEASE_NO";
  }

}

// Class B
function B(a, b, c) {
  A.apply(this, arguments);

  this.variable = "VARIABLE";
  var privateVariable = "PRIVATE_VARIABLE";

  this.bye = function () {

    return "BYE";
  }

  this.getVariable = function() { 
    return this.variable
  }

  this.getPrivateVariable = function() { 
    return privateVariable;
  }

  this.getAandB = function() {
    return a + b;
  }

  this.getFromSuperPublicPropery = function() {
    return this.publicProperty;
  }

  this.overrideThis = function() {
    return "MUHAHAHA";
  }

}

var b = new B("aaa", "bbb");

alert ( b.hello() )        // "HELLO"
alert ( b.bye() )          // "BYE"
alert ( b.getVariable() )  // "VARIABLE"
alert ( b.getPrivateVariable() ) // "VARIABLE"'
alert ( b.getAandB() )           // "aaabbb"
alert ( b.getFromSuperPublicPropery() )  // "PUBLIC_PROPERTY"
alert ( b.getPrivateProperty() ) // "PRIVATE_PROPERTY"  
alert ( b.overrideThis() ) // MUAHAHAA  


function C() {
  A.apply(this, arguments);
}

var c = new C();
alert ( c.overrideThis() ) // "NO_PLEASE_NO"
alert ( c.bye() ) // Expecting an exception here! Correct!    
mjs
  • 21,431
  • 31
  • 118
  • 200

3 Answers3

1

I think you should consider about prototypes in javascript. See this article - http://www.sitepoint.com/javascript-inheritance/.

Kirill Dubovikov
  • 1,457
  • 2
  • 21
  • 41
  • 1
    That article is not very good. It copies properties from the parent's prototype to the child's prototype. That means that `instanceof` won't work. Plus, if you modify the prototype of the parent after setting up inheritance, the child class won't pick it up. Not something that is done all the time, but it's the proper way (setting up the inheritance chain) I posted about what makes for good inheritance in JS. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html – Ruan Mendes Jun 03 '12 at 03:40
0

Like HungryMind explained what you have is not inheritance, its more like delegation. instanceof won't work for testing if it's a base class. If you prefer to create closure based objects (for private variables) instead, you're stuck with an in inheritance scheme that does not use the prototype.

See my post for what makes for correct inheritance in JS. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html Not that you can't use any other scheme, but you shouldn't until you really understand how inheritance is meant to work in JS.

Ruan Mendes
  • 90,375
  • 31
  • 153
  • 217
0

I'd suggest using the following pattern (in your example):

// A function to implement basic inheritance
function inherit(child, parent) {
  function F() {};
  F.prototype = parent.prototype;
  child.prototype = new F();
  // Reassign the original constructor, explained below
  child.prototype.constructor = child;
  // Maybe have a reference to parent prototype
  // child.superClass = parent.prototype;
}

// Class A
function A() {
}

A.prototype.hello = function() {
    return "HELLO";
}

// Class B
function B() {
    this.variable = "VARIABLE";    
}

inherit(B, A);

B.prototype.bye = function() {
    return "BYE";
}

B.prototype.getVariable = function() {
    return this.variable;
};


var b = new B();
alert ( b.hello() ) // "HELLO"
alert ( b.bye() )   // "BYE"
alert ( b.getVariable() ) // "VARIABLE"

//If you reassigned the original constructor to child, you can do the following
alert (b instanceof B); //true
alert (b instanceof A); //true

You could also override hello, as B.prototype.hello if you wished and it wouldn't reflect on the parent (object A) instances. This way you actually use prototypes to save duplicates of function definitions and ACTUALLY inherit properties, functions etc.

zatatatata
  • 4,761
  • 1
  • 20
  • 41
  • Yes, I have seen this pattern before. Not really a fan. I like the idea of having all functionality in a wrapped function. Private variables that are used in a public method would not be accessible. Right? turn this.variable to var variable = "VARIABLE"; and you would not be able to return the variable. – mjs Nov 15 '11 at 12:00
  • @Hamidam Yes, it's true that the only downside of the pattern is that it doesn't support private variables. Then again, it's the most natural (logically and memory-wise) way to do inheritance in JS. Do you ACTUALLY need private variables. They don't work as security to prevent unauthorized access to them (it's JS after all). For development-comfort, most IDEs can't see object properties anyway. For logical separation, you could name all "private" variables with leading underscore etc. – zatatatata Nov 15 '11 at 12:06
  • Yes, I do need private variables because it is much cleaner and a different coder can understand the purpose of that method or variable. If I declare a private method, then that is understood to only be used within this class. If you are writing an API this becomes a problem unless you want to spent lots of time writing clear guidelines. I have written an alternative to my initial question that do not need you to initialize an A which is the case currently, that is that I am creating two objects for one. – mjs Nov 15 '11 at 12:38
  • It's not that much cleaner, really and if clearly distinguished (1 sentence is enough), as convenient to use in APIs as private. In addition it would give you a better overview of what variables are private while modifying the original library, too. In languages where private variables are implemented, using them makes sense. In JS, where they are not, it's not the best of ideas so sacrifice code optimization and readability for something that is not worth the effort. – zatatatata Nov 15 '11 at 12:50
  • Why are you saying that private variable in JS makes no sense? Is there a way to manipulate them in a way I don't know ? Also, why would I need all the above logic ( such as the inherit method – mjs Nov 15 '11 at 12:53
  • The inherit method also creates a new instance of F, so what have I gained ? Have you seen the edited part of my original question? – mjs Nov 15 '11 at 12:59
  • @Hamidam The F is created only once, to reassign prototype property for the child. This new object is then shared among all instances of B. In your second example you create a copy of each of the sub-functions of A and B for each instance (8 in total per instance of B in your example). The idea of prototype is that all instances of the same type (either A or B) share prototype functions, therefore saving memory. In case a prototype function is called on an instance, it simply uses the original prototype function, but in the correct context. – zatatatata Nov 15 '11 at 13:06