prototype vs __proto__: Which statement is correct?

Hi,
I’m trying to understand a couple of different things. I read a lot and googled for hours. Now, I need to connect all those infos and hope that you can help me by answering this question.

Looking at this code:


    function Point(x, y) {
        this.x = x;
        this.y = y;
    }

    var myPoint = new Point();

Are the following statements correct?:

  1. Point is a Constructor function object.

  2. myPoint is an instance of Point object.

  3. Point is not the prototype of myPoint.

  4. Point is the constructor of myPoint.

  5. myPoint doesn’t have a prototype property, as prototype property is only available on functions.

  6. But myPoint has a __proto__ property like all other objects.

  7. The __proto__ property of myPoint is pointing to its prototype, which is Point.

Thanks

You’re mostly right, except for “Point is the prototype of myPoint” and “The __proto__ property of myPoint is pointing to its prototype, which is Point.” These are not correct. Point is just the constructor of myPoint, and the prototype of myPoint is actually Point.prototype.

The biggest thing to be careful of here is naming. There are “prototypes” and there are prototype properties. These are not the same thing. The prototype of any object is what its __proto__ property points to - something referred to as “[[Prototype]]” in the spec. The prototype is what an object uses to access shared properties when access is made on a property that it doesn’t have defined on its own instance.

var shared = { num: 1 };
var instance = { str: "a" };

console.log(instance.str); // "a"
console.log(instance.num); // undefined

Object.setPrototypeOf(instance, shared);

console.log(instance.str); // "a"
console.log(instance.num); // 1 <- coming from its prototype

When you create a constructor function like Point, it is created with a prototype property. This is not the prototype of the Point function object. It actually has it’s own prototype which you can access through Point.__proto__, This awkwardly named prototype property actually refers to the object which gets set as the prototype (i.e. __proto__ value) for the instances created from Point when used as a constructor with the new keyword. The prototype property would be better named as prototypeForInstancesThisConstructorCreates.

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var myPoint = new Point();
console.log(myPoint.__proto__ === Point.prototype); // true

Notice here that myPoint's prototype is being referenced by a __proto__ property (not a prototype property) and the value in the prototype property of Point is not Point's prototype. Seems a little backwards, doesn’t it?

Basically what happens is, when Point is used as a constructor, internal code in the JavaScript runtime performs this:

// pseduocode
if (is_called_with_new(current_function)) {
    this = allocate_new_object_instance()
    Object.setPrototypeOf(this, current_function.prototype)
    set_default_return_value_of(current_function, this)
}

Object.setPrototypeOf is what sets up the __proto__ link. (Note: generally the use of __proto__ is discouraged in favor of Object.setPrototypeOf and Object.getPrototypeOf, though __proto__ is what you see when debugging objects so its good to know what it means.) So what you get from new Point is a new JavaScript object that is mostly like a new {} object, but has a prototype refering to the prototype property of the function that created it. That and the function gets run with this being a reference to that object which in the case of Point here, also assigns some x and y properties to the object.

2 Likes

Oh God! I’m not sure if I understand.

Is __proto__ the same as [[Prototype]] ?

If funnyGuy object is an instance of Person, is the following diagram correct?

If it’s correct. Is the __proto__ of funnyGuy the Person object?

Yeah, the image in that you need to pay attention to, but is easily missed because it happens so early is:

The other images that follow, including the one you posted, are kind of a shorthand, especially as the prototype object goes because the prototype object in “Object” in the pictures here, actually refers to what in JavaScript would be Object.prototype.

person is actually person and not person.prototype because funnyGuy is created with

Object.create(person)

Which sets the prototype ([[Prototype]] or __proto__) to the person object directly, not its prototype property. The prototype property thing is a consequence of using new SomeConstructorFunction(). funnyGuy and person is like shared and instance in my previous example. But when it comes to person and Object, its actually person.__proto__ = Object.prototype which is not clear in these pictures.

Edit: I should mention the Something.prototype association isn’t solely a new Constructor thing since (most) all JavaScript objects ultimately point (via prototypes) back to Object.prototype and that can happen without new, for example with just {}. Objects created with {} default to having a prototype that points to Object.prototype, though this is equivalent to saying new Object() which does use new. Similarly, array literals like [1,2,3] automatically have a prototype pointing to Array.prototype and they’re also created not using new (though you can also use new Array() to create arrays).

1 Like