4

Most places where I have seen prototypes defined for a constructor it was done like so.

var Person = function(){
    this.stuff = stuff;
}
Person.prototype.doSomething = function(){console.log("something")}
var john = new Person();

But to me, coming from Java it seems more intuitive to define it directly inside the constructor.

var Person = function(){
    this.stuff = stuff;
Person.prototype.doSomething = function(){console.log("something")}
}
var john = new Person();

But the fact that I have never seen it done that way before makes me wonder if there is something wrong with doing it that way. Does it cause any problems I haven't foreseen?

  • Will it execute? I've never tried it this way; it might be possible that you can't modify the prototype until the constructor has fully executed. – Robert Harvey Aug 6 '16 at 17:36
  • Also, note that modifying the prototype causes all instances of the object to be modified, not just this instance. So putting it into the constructor of an object doesn't really make much sense. – Robert Harvey Aug 6 '16 at 17:49
  • @RobertHarvey, "modifying the prototype causes all instances of the object to be modified" not quite. You're modifying the parent prototype that all instances already refer to. You're not actually modifying any of the instances generated from the function. – zzzzBov Aug 7 '16 at 17:54
  • @zzzzBov: Yes, I get that. However, since all instances inherit from the prototype anyway, your observation is probably a distinction without a difference. As I said before, doing this in the constructor is probably a bad idea. – Robert Harvey Aug 7 '16 at 19:44
  • The distinction does make a difference, at the very least, obj.hasOwnProperty(prop) will return a different answer. They also have different uses. – Supetorus Aug 7 '16 at 22:26
5

The entire point of setting a function on a "constructor" in JavaScript is so that it's set for the prototype chain when an instance is accessed.

Example A
function Foo() {...}
Foo.prototype.bar = function () {...}
var foo = new Foo();
foo.bar(); //references the shared function on the constructor

As an alternative, functions can be set directly on instances in the constructor.

Example B
function Foo() {
  this.bar = function () {...};
}
var foo = new Foo();
foo.bar(); //references the function set directly on the instance

The difference between these two methods is in how many functions are created.

Generating a thousand instances of Foo in example A will have exactly one bar method defined and used for all instances.

Generating a thousand instances of Foo in example B will have one thousand methods created. One for each instance. This can be useful for accessing scoped variables, but comes with the obvious performance cost.


If instead you add the function to the prototype inside the constructor...

Example C: (don't ever do this)
function Foo() {
  Foo.prototype.bar = function () {...};
}
var foo = new Foo();
foo.bar(); //references the shared function on the constructor

You get the worst of both methods. You're completely unable to make use of scoped variables, because the prototype is shared, so every instance will overwrite the function and scope that's available, and you're generating a new function for each instance, and you're throwing out all the existing functions.

Don't ever write JavaScript in that manner.


tl;dr:

Is it bad to access the constructor prototype within the constructor?

Yes

  • good answer. but wouldn't trying to access Foo (or Foo.prototype) within its own definition throw an error? – chharvey Aug 7 '16 at 17:04
  • @chharvey, why should it? You're setting a property on an object just like any other object (remember, in JS, functions are first-class objects). – zzzzBov Aug 7 '16 at 17:53
  • right but I thought you can't access an object while defining it. such as var obj = { foo: 'bar', qux: obj.foo }. but maybe I'm mistaken. – chharvey Aug 7 '16 at 17:55
  • @chharvey, JS object literal notation has nothing to do with being able to access a function within a function. Additionally, it's absolutely necessary to be able to call a function within itself if you're ever going to do recursion. Furthermore, while instantiating an object instance from a function, you have access to this which is the new instance being generated, so the example you've shown would be written as: var obj = new function () { this.foo = 'bar'; this.qux = this.foo };. – zzzzBov Aug 7 '16 at 18:00
  • That is an awesome answer, however I'm confused by the result of this code in relation to what you said. var Person = function(){ Person.prototype.doSomething = function(){console.log("something")} } var john = new Person() console.log(john.hasOwnProperty(doSomething())) returns this: console.log(john.prototype.hasOwnProperty(doSomething())) ^ TypeError: Cannot read property 'hasOwnProperty' of undefined meaning the instance doesn't have the property, even though it can access it. Sorry code in this comment is formatted badly. – Supetorus Aug 7 '16 at 22:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.