James South
James South

Reputation: 10645

Prototypical inheritance and constructors

I couldn't find anything matching my exact question so sorry if this is a duplicate.

Given the code:

var Foo = function () {
};

Foo.prototype.log = function (message) {
    console.log(message);
};

var Bar = function () {
};

Bar.prototype = Object.create(Foo.prototype);

I can inherit the log(message) function of Foo within Bar and call the following code without issue.

var bar = new Bar();

bar.log("this works");

If I then move the assignment of the prototype to the constructor like follows:

var Foo = function () {
};

Foo.prototype.log = function (message) {
    console.log(message);
};

var Bar = function () {
    Bar.prototype = Object.create(Foo.prototype);
};

The call to log(message) will fail

TypeError: bar.log is not a function

Now I'm probably missing something obvious but why is this the case? How would I lazily inherit properties?

The use case I am imagining is inheriting objects from an asynchronously loaded JavaScript file, something like a google.maps.OverlayView whilst being able to already have the inherited object present in the page.

Upvotes: 0

Views: 176

Answers (2)

KooiInc
KooiInc

Reputation: 122986

When you assign the prototype within the constructor, it will be assigned after first instantiation. In the code snippet (or this jsfiddle with a few more examples and inheritance check) that situation is demonstrated in barfoo1 and barfoo2. A solution would be to copy Foo.prototype within the Bar constructor. Another solution is to return an instance on assigning the prototype within the constructor. Both are demonstrated in the FooBar and FooFoo constructor in the snippet respectively.

Furthermore you can assign the prototype just using Xyz.prototype = Abc.prototype (no need for Object.create here), or use Xyz.prototype = new Abc.

var Foo = function () {};

Foo.prototype.log = function (msg) {
  log(msg);
}

var Bar = function () {
    Bar.prototype = Object.create(Foo.prototype);
};

var FooBar = function () {
  if (!FooBar.prototype.log) {
     for (var l in Foo.prototype) {
       FooBar.prototype[l] = Foo.prototype[l];
     }
  }
}

var FooFoo = function () {
  if (!FooFoo.prototype.log) {
       FooFoo.prototype = new Foo;
       return new FooFoo;
    }
}

var BarFoo = function () {
  if (!BarFoo.prototype.log) {
       BarFoo.prototype = Object.create(Foo.prototype);
  }
}

var bar = new Bar;
var foobar = new FooBar;
var barfoo1 = new BarFoo; 
var barfoo2 = new BarFoo;
var doublefoo = new FooFoo;

try { bar.log('hello!'); }
catch(e) {log('bar.log failed => ', e.message);}

try { barfoo1.log('barfoo1 hello!'); }
catch(e) {log('barfoo1.log failed => ', e.message);}

try { barfoo2.log('barfoo2 hello!'); }
catch(e) {log('barfoo2.log failed => ', e.message);}

foobar.log('foobar just works (Foo.prototype copied)');
doublefoo.log('doublefoo just works too (instantiation on assigning Foo.prototype)');

function log() {
  document.querySelector('#result')
    .innerHTML += '<p>'+ [].slice.call(arguments).join('') +'</p>';
}
<div id="result"></div>

Upvotes: 1

Siva Senthil
Siva Senthil

Reputation: 610

James if jQuery is possible in your code you could attempt something like this -

var Bar = function() {};
$.ajax({
  url: "http://maps.google.com/api/scriptfile.js",
  dataType: "script",
  success: function(script, status) {
             Bar.prototype = Object.create(Foo.prototype);
           }
});

Hope this helps!

Upvotes: 0

Related Questions