1

I tend to write my Javascript "classes" in c-style.

In C# (for example) we do this

public class Parent {
 // stuff
}
public class Child : Parent {
 // Protected and public stuff from Parent will be accessible
}

In JS I found the equivalent of this by using proto, in example

var namespace = namespace || {};
namespace.Parent = function() {
 // Public variables
 self.pubVariable = "I am accessible";
 // Private variables
 var priVariable = "I'm not accessible outside of self";
 // ctor
 function self() {}
 return self;
}
namespace.Child = (function() {
 this.__proto__ = new namespace.Parent();
 // ctor
 function self() {}
 self.init = function() {
 // Prints the pubVariable
 console.log(pubVariable);
 };
 return self;
})($);
// Call it (statically) 
namespace.Child.init();

While this works it is Webkit and Mozilla only. I've understood that this could somehow be achievable using prototype but can't figure out how. Any advice is appreciated. Thanks!

asked Jun 23, 2013 at 17:20
9
  • Why do you use an IIFE for the child, but not for the parent? It doesn't seem like this code would ever work. Commented Jun 23, 2013 at 17:39
  • 2
    Why are you writing classes in a style from a language with an entirely different class system? javascript classes CAN be made to act "like" C (or classical) classes, but you're going to find it's much easier to stop working against it and go with the flow. Commented Jun 23, 2013 at 17:45
  • @Bergi, the code works just fine in webkit/moz. All public variables and methods from the parent is accessible in the child. Commented Jun 23, 2013 at 17:48
  • @tkone, it is a very nice approach to have the methods and variables from the parent in the child so why not? Commented Jun 23, 2013 at 17:49
  • @EricHerlitz: If this really works, then you're abusing a lot of things. Basically you're setting the prototype of the global object to the parent's self function, that its property is available as a variable everywhere. This is completely wrong. Commented Jun 23, 2013 at 17:56

2 Answers 2

6

For parent/child classes, I would do something like this

// your parent class
var Parent = function() {
 // parent constructor
 console.log("parent constructor!");
 
 // some public properties
 this.foo = "foo";
 this.bar = "bar";
 // a private data member
 var secret = "123456";
};
// a parent function
Parent.prototype.something = function() {
 console.log("something!");
}
// your child class
var Child = function() {
 
 // call parent constructor
 Parent.call(this); 
 
 // child constructor
 console.log("child constructor!");
 // override bar
 this.bar = "override!";
};
// the magic!
// child prototype build from parent prototype
Child.prototype = Object.create(Parent.prototype, {constructor: {value: Child}});

Example usage

var c = new Child();
c.something();
// => parent constructor!
// => child constructor!
// => something!
c.foo //=> "foo"
c.bar //=> "override!"

If you're using "namespacing" the concept is identical.


EDIT

Per your comment, here's and added demonstration

var Foo = function(){};
Foo.prototype.hello = function(){ return "hello!"; };
var foo = new Foo();
// call our hello method
// this calls foo.__proto__.hello
foo.hello(); //=> "hello!"
// override `hello` method for this instance
foo.hello = function(){ return "こんにちは"; };
// call our hello method again
// this calls foo.hello because it is defined directly on our instance
// (it has a higher precedence in the lookup chain)
foo.hello(); //=> "こんにちは"
// remove the override
delete foo.hello;
// call our hello method again
// this goes back to calling foo.__proto__.hello
foo.hello(); //=> "hello!"
// remove the method prototype
delete Foo.prototype.hello
// call our hello method one last time
// spoiler: it's gone!
foo.hello(); //=> TypeError: Object [object Object] has no method 'hello'

As you can see, you lose this functionality by directly defining methods on the instance using this.something = function(){};. I personally prefer defining methods on the prototype because of the added flexibility. This way, the prototype really works like a blueprint. You get all the pre-defined behavior; you can modify if necessary and revert to the original whenever you want, all on a per-instance basis.


ONE MORE THING

In our last example, we had a prototype method and an instance method override. Is there a way to call the original method too? Let's see!

var Foo = function(){};
Foo.prototype.hello = function(){ return "hello!"; };
var foo = new Foo();
foo.hello = function(){ return "こんにちは!"; }
// call override method
foo.hello(); //=> "こんにちは!"
// call original method
Foo.prototype.hello.call(foo); //=> "hello!"
// japanese just one more time...
foo.hello(); //=> "こんにちは!" 

This would work too, but I never really have the need. I suppose the benefit is you don't need to know the original class this way :)

// call original method from the instance
foo.__proto__.hello.call(foo); //=> "hello!"

PROTOTYPES!

answered Jun 23, 2013 at 17:39
Sign up to request clarification or add additional context in comments.

4 Comments

+1; it would be nice if you could comment a little bit on the private variables and public properties and how they are "inherited"
I created a fiddle using achieving the same behavior as yours by instead putting the prototype method 'something' inside the Parent class, is there a reason not to do that? jsfiddle.net/XzxRw
@EricHerlitz, they both operate pretty similarly and you'd mostly likely not run into an issue here. The difference is mine is attached to Parent.prototype and yours is attached to myParent (an instance of the Parent class). I prefer attaching instance functions to the prototype and then when necessary, defining instance-level overrides directly on the instance.
@EricHerlitz, I updated my answer one more time to demonstrate the power of prototypes a little bit better :>
1

I think, you want this

// namespace
var namespace = namespace || {};
// Parent Class
namespace.Parent = function() {
 this.pubVariable = "I am accessible";
 var priVariable = "I'm not accessible outside of this";
}
// Child class
namespace.Child = function() {
 // namespace.Parent.call(this);
 this.init = function()
 {
 // returns Parent class' pubVariable
 // inherited by namespace.Child.prototype
 return this.pubVariable;
 }
};
// inherit Parent class
namespace.Child.prototype = new namespace.Parent();
var kid = new namespace.Child();
console.log(kid.init()); // I am accessible

If you use namespace.Parent.call(this) then Child class will have it's own copy of pubVariable but now Child class is using Parent's pubVariable.

Also, if you want to share methods from parent class with sub classes then you should add methods in the parent class' prototype, like this

namespace.Parent = function() { //... }
namespace.Parent.prototype.aMethodInParent = function(){ //... };

So, when you will inherit it in a subclass like this

namespace.Child = function() { // ... };
namespace.Child.prototype = new namespace.Parent();

Another Sub/Child Class

namespace.AnotherChild = function() { // ... };
namespace.AnotherChild.prototype = new namespace.Parent();

In this case both sub/child classes will use the same aMethodInParent() method from their parent class.

DEMO.

answered Jun 23, 2013 at 17:59

4 Comments

Exactly! This allows me to separate subsets of methods and classes into their own objects while still being able to access the goodies of the parent.
Right. If you want to share methods with sub class then you must add methods in the prototype of parent class.
Don't use new for inheriting the parent class!
Can you explain why not new ?

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.