Skip to content Skip to sidebar Skip to footer

Javascript Inheritance And Hoisting

In my current web project, I'm working with multiple JavaScript files, each containing type definitions that inherit from other types. So in any given file, I could have something

Solution 1:

For multi-link prototype chains, if the statements are out of order, the chain fails to connect properly.

Yes. You need to set Type.prototype before using it to create ChildType.prototype. This doesn't have to do anything with the hoisting of the function declarations.

Is there a way to implement inheritance in JavaScript that "works" regardless of the order in which my files are concatenated?

Well, you can might use Object.setPrototypeOf:

functionChildType(){
    Type.call(this);
}
Object.setPrototypeOf(ChildType.prototype, Type.prototype);

functionType(){
    ParentType.call(this);
}
Object.setPrototypeOf(Type.prototype, ParentType.prototype);

functionParentType(){
    this.data = "";
}

However, you really really want to avoid that method, and relying on hoisting like this is a very bad practice, so you really should fix your concatenation script to use the correct order. Or use a module system that figures dependencies out for you.

My first though was the class and extends way of doing things, but then I learned that even class definitions aren't hoisted!

That's a good thing. Just consider them to be purely sugar - you always need to set them up in the correct order, following the hierarchy.

Solution 2:

The functions are hoisted, so they can be out of order, but the calls to chain the prototypes must be in order.

If they are out of order, your code will look like the following after hosting.

functionParentType(){
  this.data = "";
}

functionType(){
    ParentType.call(this);
}

functionChildType(){
    Type.call(this);
}
ChildType.prototype = Object.create( Type.prototype );
ChildType.prototype.constructor = ChildType;

Type.prototype = Object.create( ParentType.prototype );
Type.prototype.constructor = Type;

That is, you chain ChildType.prototype toType.prototype and then you overwrite Type.prototype to chain it to ParentType.prototype.

There is no way to make this work out of order, JavaScript inheritance depends on those lines of code being called in order.

Solution 3:

One way to do it is to declare a static initializer for each type.

However, this is only possible at execution runtime (via Object.crate or via assignment) and therefore we are back at start. If your files are really concatenated in random order, then you should use more complex mechanisms with a sort of "factory" function that will create the types as they appear and put subtypes "on hold" until their parent is created.

Simplified example just for illustration purposes:

functionfactory(precondition, callback)
{
     if( !this.registry ) this.registy = [];
     if( !precondition || this.registry[precondition] ) 
         this.registry[callback()] = true;
     elsesetTimeout(function(){factory(precondition, callback);}, 100);
}

factory('Type', function()
{
     Window.ChildType = function(){}
     return'ChildType';
});

factory(null, function()
{
     Window.Type= function(){}
     return'Type';
});

Post a Comment for "Javascript Inheritance And Hoisting"