1

I am curious as to what's going on here. As you can see, I have defined a constructor function called range to build new range objects. I've extended the range constructor through it's prototype, adding a simple includes method. I've created my new object and used the variable of p. When I attempt to use this method with my range objects, all is well and it works as expected. The problem is when I try to look at at p.prototype it tells me that it's type is undefined and p.prototype has no methods... Huh??

What's going on here?? How is p an object and p.prototype is not?

    function range(from, to) {
        this.from = from;
        this.to = to;
    }


    range.prototype = {
        includes: function(x) { return this.from <= x && x <= this.to; },
    }

    var p = new range(1, 4);

    console.log(typeof p) //outputs object
    console.log(typeof p.prototype) //outputs undefined

    console.log(Object.getOwnPropertyNames(range.prototype)); //outputs includes
    console.log(Object.getOwnPropertyNames(p.prototype)); //throws error, p.prototype is not an object

4 Answers 4

2

The problem is when I try to look at at p.prototype it tells me that it's type is undefined

That's correct. The objects created by your range constructor do not have a prototype property, but they do have an underlying prototype (which is drawn from the prototype property of the range function).

Let's look at what happens when you do new range():

  1. The JavaScript engine creates a new, blank object.
  2. The JavaScript engine assigns that object's underlying prototype (not prototype) to be the object referenced by range.prototype. (In the spec, this property — which is not directly accessible in code but see below — is called [[Proto]].)
  3. The JavaScript engine calls range with this referring to the new object.
  4. Assuming range doesn't return a different object (which it can do; this is a bit obscure), the result of new range is the new object created in step 1.

Later, when you use this.includes, this is what happens:

  1. The engine looks at the actual object to see if it has an includes property.
  2. Since it doesn't, the engine looks at [[Proto]] to see if it has one.
  3. Since it does, it uses that one (if not, it would have looked at [[Proto]]'s [[Proto]] and so on).

The key things here are:

  1. Objects have underlying prototypes, which are not accessible via any named property on the object itself. (In fact, it used to be we couldn't get to them at all. Now, in ES5, we have Object.getPrototypeOf.)
  2. Objects created via new SomeFunctionName get their prototype from SomeFunctionName.prototype property, which is a perfectly normal property of the SomeFunctionName object (functions are first-class objects in JavaScript).

Side note: You're replacing the prototype of range with your code. In general, although it works, I would avoid that. Instead, augment the existing object referred to by range.prototype. (Add properties to it, rather than replacing it.) But that's not central to your question.

Sign up to request clarification or add additional context in comments.

8 Comments

Well, how am I able to use any of these methods defined in range.prototype if p has no prototype?
@SethenMaleno: By simply referring to them from p (e.g., p.includes).
read this article - javascriptweblog.wordpress.com/2010/06/07/… - will be very useful.
The fundamental idea to grok here is that, in Javascript, there are no classes. Objects inherit from other objects.
How am I replacing the prototype with what I have at the top? The reason I wrote it that way was to extend it with a lot of different methods.
|
0

I think you wanted was:

range.prototype.includes = function(x) { 
    return this.from <= x && x <= this.to; 
}

5 Comments

I am not sure how this is any different than I have it. I have written it to define multiple methods in an the prototype object.
This still throws errors. Not sure how this answers my question.
While it's true that Sethen is replacing the prototype, that's a perfectly valid thing to do (though I don't recommend it) and is not the source of the behavior he's seeing. Also, from and to were never part of the prototype at all. They were (and remain) parts of the objects created via new range. The fact that Sethen is replacing the prototype has exactly no effect on them.
The same ones outlined in the original question.
I think T.J. Crowder has laid it out for you pretty clearly. You can call Object.getOwnPropertyNames(p.prototype). It is supposed to give you an error.
0

You redefined the prototype object, so the reference to the original one has disappeared. Try this way:

range.prototype.includes = function(x) { 
    return this.from <= x && x <= this.to;
}

1 Comment

While this is true, it's not the source of the behavior in question.
0
Number.prototype.myRound = function (decimalPlaces) {
    var multiplier = Math.pow(10, decimalPlaces);

    return (Math.round(this * multiplier) / multiplier);
};

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.