2
var a = function(){
    this.sayFoo = function(){
        console.log('foo');
    };
}

var b = function(){
    console.log(this.prototype); //undefined
    this.sayBar = function(){
        console.log('bar');
    };
}

b.prototype = new a();

var bInst = new b();

bInst.sayFoo();
bInst.sayBar();

console.log(b.prototype); //a {sayFoo: function}

http://jsfiddle.net/KbBny/1/

How do I add sayBar to the b prototype inside the function constructor?

Does b.prototype = new a(); overwrite the prototype, or merge b's with a's?

Johan
  • 35,120
  • 54
  • 178
  • 293
  • 1
    The whole idea of a prototype is that you define it *outside* of the constructor, rather than inside. – Ja͢ck May 16 '13 at 08:55
  • Read this: http://stackoverflow.com/a/8096017/783743 – Aadit M Shah May 16 '13 at 08:57
  • I can totally understand the wish to set the property inside the constructor, because setting it outside looks so disconnected. Added my own wrapperbased solution further down. – brat Dec 02 '18 at 03:15

3 Answers3

2

You are not using the correct inheritance pattern.

Use:

b.prototype = Object.create(a.prototype);

In your case you are performing a simple override, you are not correctly establishing inheritance. Object.create is ES5, but you could polyfill with this:

Object.create

if (!Object.create) {
    Object.create = function (o) {
        if (arguments.length > 1) {
            throw new Error('Object.create implementation only accepts the first parameter.');
        }
        function F() {}
        F.prototype = o;
        return new F();
    };
}

Accessing the prototype

You can't access the prototype inside the definition block. You have a this reference for that.

var b = function() {
    a.call(this);
    b.prototype.doSomething = function() {console.log("b");}; 
};
b.prototype = Object.create(a.prototype);

DEMO

flavian
  • 28,161
  • 11
  • 65
  • 105
  • Does this merge the prototypes? And how is the browser support for `Object.create`? – Johan May 16 '13 at 08:36
  • Thanks, would it be enough to include the source for `Object.create` in order to support it in older browsers? Or does it rely on other functions? – Johan May 16 '13 at 08:38
  • @Johan https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/create#Polyfill – Fabrício Matté May 16 '13 at 08:40
  • Ok, and the final question which I don't believe you have answered yet. How do I access the b prototype inside the function? – Johan May 16 '13 at 08:41
  • @alex23 Inside the `b` constructor function. – Johan May 16 '13 at 08:45
1

Does b.prototype = new a(); overwrite the prototype, or merge b's with a's?

It does overwrite it with a new a instance; nothing is merged (for example you'd need to update the b.prototype.constructor property). That's why you do add all properties to b.prototype after this line. However, actually you don't want to create an instance, but just set up the prototype chain correctly:

b.prototype = Object.create(a.prototype);

How do I add sayBar to the b prototype inside the function constructor?

You should not add it to the prototype, as it is not a prototype (shared) method - it's instance-specific to every a instance (at least it should be, otherwise you would put it on a.prototype and then it gets covered by above line). To get the instance method on all b instances as well, you use

var b = function(){
    a.call(this); // invoke the `a` constructor on this instance
};
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • Hmm, not sure if I'm following you on the last part. If I use `this.sayBar = ...` inside the b construcor function, it would have to be redefined for each instance of b, right? Wouldn't it be better to add it to the prototype? – Johan May 16 '13 at 08:44
  • 1
    @alex23 no, functions are _not_ always in the prototype. – Alnitak May 16 '13 at 08:46
  • @alex23 Then please explain why I don' see two methods in the console: http://jsfiddle.net/KbBny/2/ – Johan May 16 '13 at 08:47
  • @alex23 no, a function added with `this.func = function() { ... }` is a direct property of that object, and doesn't touch the prototype at all. – Alnitak May 16 '13 at 08:47
  • @alex23: No, not those on `this`. You really should read [prototype vs this](http://stackoverflow.com/q/310870/1048572) – Bergi May 16 '13 at 08:48
  • @Alnitak Would it be possible to add something to the prototype inside of the constructor function? – Johan May 16 '13 at 08:50
  • @Johan it's possible, but you shouldn't do it, because the constructor is called once _per instance_, but the prototype is shared amongst _all_ instances. – Alnitak May 16 '13 at 08:50
  • 1
    @Johan: correctly. Your `sayFoo` and `sayBar` functions are currently redefined for each instance. Since they don't need access to any closure variables, they better should be on the prototype. And don't listen to alex23. – Bergi May 16 '13 at 08:51
  • @Alnitak Yes, I know. That's why I want to add stuff to the prototype instead of `this`. But I suppose that I can't add it inside the constructor then. – Johan May 16 '13 at 08:52
  • That's right. And the corollary of that is that functions on the prototype cannot access lexically scoped variables bound inside the constructor. – Alnitak May 16 '13 at 08:53
0

prototype Sort of inside constructor

You could use a wrapping function. I believe they are called decoratorfunctions in Javascript. Where you set the prototype. And then when you use that decoratorfunction as a constructor, you wont have to set the prototype separately. It will so to speak be set inside a function that acts as a constructor.

function Human(name, lastname, age) {
  function _human(name, lastname, age) {
    this.name = name;
    this.lastname = lastname;
    this.age = age;
  }
  _human.prototype.sayName = function() {
    console.log(this.name + " " + this.lastname);
  }
  var temp = new _human(name, lastname, age);
  return temp;
}

Then you just do:

var person = new Human("John", "Doe", 25);
console.log(person);
person.sayName();
Community
  • 1
  • 1
brat
  • 586
  • 5
  • 17