Subclassing with .prototype and __proto__

I recently studied javascript by writing some gnome shell extensions, and so my understanding of Javascript was generated by the examples I observed in gnome-shell javascript sources. I have a feeling that I misunderstand classes and just want to clarify.

I wrote some of my subclasses, and in each case I defined them simply by executing the same code in the javascript source of the gnome shell:

Subclass = function() { this._init.apply(this,arguments); } Subclass.prototype = { __proto__: Superclass.prototype, _init: function() { Superclass.prototype._init.call(this); }, // add other methods of Subclass here. } 

So far, I thought this was the standard way to create a Subclass class, which was basically Superclass plus additional features. I assumed that every object has a _init method.

I recently tried to use the same method to subclass Clutter.Actor (which is important because it is not a class defined by the GNOME shell), and realized that the above method of subclass objects is not standard. First, not every class has a _init function, as I suggested; this is what the GNOME shell did in its javascript classes.

So my questions are :

  • Is there any documentation regarding the above subclassing method? In all the tutorials I've seen, you need to set Subclass.prototype = new Superclass() instead of making the Subclass.prototype = { __proto__:Superclass.prototype, define_prototype_methods_here } , but I suppose there should be some method if gnome-shell uses it sequentially?
  • If I wanted to be as close as possible to the class definition described above (just to preserve some similarities between the code and the GNOME shell for which I am writing extensions) , that I can replace Superclass.prototype._init.call(this) with in Subclass._init to make sure that Subclass.prototype gets all the Superclass methods / properties (which I then add in my Subclass.prototype definition) if Superclass doesn't have a _init function (i.e. does it have some kind of equivalent constructor function that I call)?

I am really confused by this, so please forgive me if my question does not make much sense; it will be due to my misunderstanding and confusion!

EDIT : clarification: - I know that __proto__ not recommended because it is non-standard, but my code will never run in the browser - it will only work with GNOME javascript (which is basically Mozilla's javascript mechanism), so I don’t have to worry about cross-compatibility.

+5
javascript
May 14 '12 at 8:53
source share
3 answers

As already mentioned, do not use __proto__ . This is a non-standard property. (It is now standardized for JavaScript in browsers. Still don't use it.) But

 Subclass.prototype = new Superclass(); // Don't do this 

also not a good method. What if Superclass expects parameters?

You have the best options.

ES2015 and above

class handles all this plumbing for you; full example:

 class Superclass { constructor(superProperty) { this.superProperty = superProperty; } method() { console.log("Superclass method says: " + this.superProperty); } } class Subclass extends Superclass { constructor(superProperty, subProperty) { super(superProperty); this.subProperty = subProperty; } method() { super.method(); // Optional, do it if you want super logic done console.log("Subclass method says: " + this.subProperty); } } let o = new Subclass("foo", "bar"); console.log("superProperty", o.superProperty); console.log("subProperty", o.subProperty); console.log("method():"); o.method(); 

ES5 and earlier

Let Subclass.prototype inherit only from Superclass.prototype . This can be done, for example, using ES5 Object.create :

 Subclass.prototype = Object.create(Superclass.prototype); Subclass.prototype.constructor = Subclass; 

And then in Subclass you call Superclass with this , referencing the object so that it can initialize:

 function Subclass() { Superclass.call(this); // Pass along any args needed } 

Full example:

 function Superclass(superProperty) { this.superProperty = superProperty; } Superclass.prototype.method = function() { console.log("Superclass method says: " + this.superProperty); }; function Subclass(superProperty, subProperty) { Superclass.call(this, superProperty); this.subProperty = subProperty; } Subclass.prototype = Object.create(Superclass.prototype); Subclass.prototype.constructor = Subclass; Subclass.prototype.method = function() { Superclass.prototype.method.call(this); // Optional, do it if you want super logic done console.log("Subclass method says: " + this.subProperty); }; var o = new Subclass("foo", "bar"); console.log("superProperty", o.superProperty); console.log("subProperty", o.subProperty); console.log("method():"); o.method(); 

ES3 and earlier

ES3 doesn't have Object.create , but you can easily write a function that sets up a prototype for you in much the same way:

 function objectCreate(proto) { var ctor = function() { }; ctor.prototype = proto; return new ctor; } 

(Note: You can half-shim Object.create by creating one that takes only one argument, but the option with multiple arguments to Object.create cannot be Object.create , so it will give the other code on the page the wrong idea if it also uses Object.create .)

Then you do the same as our ES5 example:

Full example:

 function objectCreate(proto) { var ctor = function() { }; ctor.prototype = proto; return new ctor; } function Superclass(superProperty) { this.superProperty = superProperty; } Superclass.prototype.method = function() { console.log("Superclass method says: " + this.superProperty); }; function Subclass(superProperty, subProperty) { Superclass.call(this, superProperty); this.subProperty = subProperty; } Subclass.prototype = objectCreate(Superclass.prototype); Subclass.prototype.constructor = Subclass; Subclass.prototype.method = function() { Superclass.prototype.method.call(this); // Optional, do it if you want super logic done console.log("Subclass method says: " + this.subProperty); }; var o = new Subclass("foo", "bar"); console.log("superProperty", o.superProperty); console.log("subProperty", o.subProperty); console.log("method():"); o.method(); 
+5
May 14 '12 at 9:29 a.m.
source share

Although __proto__ now standardized as a required extension for JavaScript when used in web browsers, it makes no sense to use it when setting up the inheritance hierarchy.

Instead, use Object.create (an ES5 function, the key parts of which for our purposes here can be customized if you really need to support an outdated browser).

Here is an example when

 var BaseClass = function() { }; var SubClass = function() { // Important that SubClass give BaseClass a chance to init here BaseClass.call(this/*, args, if, necessary, here*/); // ... }; // Make `SubClass` `prototype` an object that inherits from // `BaseClass` `prototype`: SubClass.prototype = Object.create(BaseClass.prototype); // Fix up the `constructor` property SubClass.prototype.constructor = SubClass; 

What is it.

If the BaseClass constructor requires an argument, you pass it an argument to SubClass :

Here is an example when

 var BaseClass = function(arg) { this.prop = arg; }; var SubClass = function(baseArg) { // Can accept it, or provide a BaseClass.call(this, baseArg); // hardcoded one here // ... }; SubClass.prototype = Object.create(BaseClass.prototype); SubClass.prototype.constructor = SubClass; 



Of course, with ES2015 (aka ES6) you can just use class (and translate if necessary).

 class BaseClass { constructor(arg) { this.prop = arg; } } class SubClass extends BaseClass { constructor(baseArg) { super(baseArg); } } 
+1
Oct 08 '16 at 14:33
source share

__proto__ should never be used in your code, as it is used in the JavaScript Engine implementation to return to the prototype for defining an object class. refer: MDN: __proto__

1>

  Subclass.prototype = new Superclass(); 

is the correct way to inherit a superclass.

2> if you want to call _init in a subclass that actually executes the Superclass _init method, then do not define its definition in the SubClass class. When you try to access the _init method on subClass (an instance of the SubClass object), the JS engine tries to find it in the current obj, if the method is not found, it runs in the SubClass prototype chain (i.e. SuperClass)

if you want to call a superclass method inside a subclass method, use

 Superclass.prototype._init.call(this) 

performance of superfunction in the field of current objects This does the trick of calling the super method in the SubClass method

0
May 14 '12 at 9:16
source share



All Articles