1

I'm working with a fairly simple Point2D data structure I built to be inheritable for say a Point3D in the future and I've followed all the guides and similar questions I can find, but none seem help with my issue.

I've defined Point2D as follows:

function Point2D (px, py)
{
  this.x = px;
  this.y = py;

  Point2D.prototype =
  {
    constructor: Point2D,

    move:function (mx, my)
    {
      this.x = mx;
      this.y = my;
    },
    translate:function (dx, dy)
    {
      this.x += dx;
      this.y += dy;
    }
  };
};

I instantiate the object as follows:

var p2d1 = new Point2D(2,3);

Then I call one of the methods as follows:

p2d1.move(1,2);

And the result is:

TypeError: Object #<Point2D> has no method 'move'

I have not idea why my methods don't resolve.

I've messed around with it for a good while and found that I can declare Point2D methods this way and they will work.

Point2D.prototype.move = function () {};

Can anyone explain why they first style of replacing the entire prototype does not work, but adding functions to the existing prototype does work?

Austin
  • 576
  • 2
  • 8
  • 21

3 Answers3

2

When you call new Point() the first time, Point.prototype is still an "empty" prototype. I.e. the instance that is created doesn't inherit any methods.

You change (replace) the prototype after the instance was already created. JavaScript has assign by value, not assign by reference. Quick example:

var a = 5;
var b = {c: a};
a = 10;

b.c is still 5, since assigning to a doesn't change what b.c refers to.

Point2D.prototype.move = function () {};

works because you are not replacing Point2D.prototype, you are simply mutating the existing object.

Overall, assignments to *.prototype should take place outside the constructor:

function Point2D (px, py) {
  this.x = px;
  this.y = py;
};

Point2D.prototype = { };
Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
1

I am not sure, but defining the prototype inside the declaration of the "class" is unusual and to me, hard to define exactly how things would be resolved. When doing manual inheritence, I tend to follow more these patterns:

function Foo() {
   this.bar = ...
}

Foo.prototype.baz = function() { ... }

OR

function Foo() { ... }
function Bar() { ... }

Foo.prototype = new Bar();

OR

Foo.prototype = {
    blah: ...
}

Also I wouldn't usually create a "constructor" property manually, as this is a side effect of setting the prototype, but I know some popular libraries do this. In the middle example above, Foo.prototype.constructor == Bar.

Jason Boyd
  • 1,192
  • 1
  • 9
  • 19
0

If you really want to warp your brain create a second instance of Point2D and watch it have the move method available and working!

So here is what is happening.

define Point2D class
create instance of Point2D class
  create initialization object
  create execution context object per new keyword usage
  attach prototype to execution context (at this point just Object)
  run constructor method
    assign value of x
    assign value of y
    assign new prototype value to Point2D class

what you want to do is to move the prototype setting out to the same scope as the class definition.

Gabriel
  • 18,322
  • 2
  • 37
  • 44