3

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?

5
  • 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. Aug 6, 2016 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. Aug 6, 2016 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, 2016 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. Aug 7, 2016 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, 2016 at 22:26

1 Answer 1

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

11
  • good answer. but wouldn't trying to access Foo (or Foo.prototype) within its own definition throw an error?
    – chharvey
    Aug 7, 2016 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, 2016 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, 2016 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, 2016 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, 2016 at 22:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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